添加新组件时(每当按下按钮时)是否有更简单的方法将 'older' 组件向下移动?

Is there an easier way to shift 'older' components down when adding newer components (whenever a button is pressed)?

我尝试寻找我的问题的答案,但找不到任何类似的答案。如果已经有人问过,请 link。提前致谢。

主面板mainPanel的布局为GridBagLayout。它有三个按钮。其中两个是哑弹(出于这个问题的目的)。每次按下 butt2 时,中间按钮 butt2 都会创建一个包含其他组件的 JPanel。

因为butt2在中间,而butt3在它的正下方,我有一个int变量tracker2,它跟踪butt2的网格。每次按下 butt2 时,我都会在 butt2 下创建一个新的 JPanel,增加 tracker2,然后删除 butt3 并将其添加到较新的组件下方。

import java.util.List;
import java.util.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

import javax.swing.*;

 public class Demo implements ActionListener 
     public static void main(String[] args) {
         Demo demo = new Demo();
     }

     private JFrame frame;
     private JPanel mainPanel;
     private JButton butt1, butt2, butt3;
     private GridBagConstraints gb;
     private List<JTextField> list;
     private int count, tracker2;

     public Demo() {
         frame = new JFrame("Demo");
         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         frame.setResizable(true);
         frame.setBounds(0, 0, 800, 800);
         list = new ArrayList<JTextField>();
         count = 0;
         tracker2 = 0;

         commence();
     }

     private void commence() {
         gb = new GridBagConstraints();
         gb.anchor = GridBagConstraints.FIRST_LINE_START;
         gb.weightx = 1;
         gb.insets = new Insets(50, 5, 0, 20);

         mainPanel = new JPanel();
         mainPanel.setBackground(Color.white);
         mainPanel.setLayout( new GridBagLayout() );

         butt1 = new JButton("One");
         butt1.setPreferredSize( new Dimension(100, 50) );
         // Add to panel
         gb.gridx = 0;
         gb.gridy = 0;
         mainPanel.add( butt1, gb);

         butt2 = new JButton("Two");
         butt2.setPreferredSize( new Dimension(100, 50) );
         butt2.addActionListener(this);
         // Add to panel
         gb.gridy++;
         tracker2 = gb.gridy;
         mainPanel.add( butt2, gb );

         butt3 = new JButton("Three");
         butt3.setPreferredSize( new Dimension(100, 50) );
         // Add to panel
         gb.gridy++;
         mainPanel.add( butt3, gb );

         frame.add(mainPanel);
         frame.setVisible(true);
         frame.repaint();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if(e.getSource().equals( butt2 )) {
            commence2();
        }
    }

    private void commence2() {
        gb.insets = new Insets( 0, 0, 0, 0 );
        list.add( new JTextField(30) );

        JLabel label = new JLabel("LABEL 2   ");
        label.setDisplayedMnemonic( KeyEvent.VK_N );
        label.setLabelFor( list.get(count) );

        JPanel panel = new JPanel( new FlowLayout(FlowLayout.LEFT, 10, 3));
        panel.setBackground( Color.white );
        panel.add(label);
        panel.add(list.get( count ));
        // Add to mainPanel
        tracker2++;
        gb.gridy = tracker2;
        mainPanel.add( panel, gb );
        updateFrame();
        // Increment count
        count++;

        frame.revalidate();
        frame.repaint();
    }

    private void updateFrame() {
        mainPanel.remove( butt3 );
        gb.insets = new Insets(50, 5, 0, 20);
        gb.gridy = tracker2 + 1;
        mainPanel.add( butt3, gb );
    }
}

是否有更简单的方法或自动为我执行此操作的布局?

是的,有更简单的方法。不要将新文本字段添加到 mainPanel,而是使用额外的 Container。例如

public class Demo2 implements ActionListener {
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      @Override
      public void run() {
        new Demo2();
      }
    });
  }

  private JFrame frame;
  private JPanel textPanel;
  private JButton butt1, butt2, butt3;

  public Demo2() {
    frame = new JFrame("Demo");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setResizable(true);
    frame.setBounds(0, 0, 800, 800);

    commence();
  }

  private void commence() {
    GridBagConstraints gb = new GridBagConstraints();
    gb.anchor = GridBagConstraints.FIRST_LINE_START;
    gb.weightx = 1;
    gb.insets = new Insets(50, 5, 0, 20);

    JPanel mainPanel = new JPanel();
    mainPanel.setBackground(Color.white);
    mainPanel.setLayout( new GridBagLayout() );

    butt1 = new JButton("One");
    butt1.setPreferredSize( new Dimension(100, 50) );
    // Add to panel
    gb.gridx = 0;
    gb.gridy = 0;
    mainPanel.add( butt1, gb);

    butt2 = new JButton("Two");
    butt2.setPreferredSize( new Dimension(100, 50) );
    butt2.addActionListener(this);
    // Add to panel
    gb.gridy++;
    gb.insets = new Insets(50, 5, 0, 0);
    mainPanel.add( butt2, gb );

    textPanel = new JPanel(new GridLayout(0, 1));
    // Add to panel
    gb.gridy++;
    gb.insets = new Insets(0, 5, 0, 20);
    mainPanel.add( textPanel, gb );

    butt3 = new JButton("Three");
    butt3.setPreferredSize( new Dimension(100, 50) );
    // Add to panel
    gb.gridy++;
    gb.insets = new Insets(50, 5, 0, 20);
    mainPanel.add( butt3, gb );

    frame.add(mainPanel);
    frame.setVisible(true);
    frame.repaint();
  }

  @Override
  public void actionPerformed(ActionEvent e) {
    if(e.getSource().equals( butt2 )) {
      commence2();
    }
  }

  private void commence2() {
    JTextField jtf = new JTextField(30);

    JLabel label = new JLabel("LABEL 2   ");
    label.setDisplayedMnemonic(KeyEvent.VK_N );
    label.setLabelFor( jtf );

    JPanel panel = new JPanel( new FlowLayout(FlowLayout.LEFT, 10, 3));
    panel.setBackground( Color.white );
    panel.add(label);
    panel.add( jtf );

    // Add to mainPanel
    textPanel.add( panel );
    textPanel.revalidate();

    frame.revalidate();
    frame.repaint();
  }
}

在上面的代码中,textPanel 用作新文本字段的容器。