You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Swing中单列与两列布局的GUI合并为一个应用

Swing GUI合并与布局方案疑问

我已经开发了两个Swing GUI应用:一个采用单列布局,另一个采用两列布局,两款应用的截图如下:

单列布局应用截图

两列布局应用截图

问题

我希望把这两个GUI合并成一个应用。第二个应用基于GroupLayout实现,代码整洁且无需手动定位组件,但很多教程都指出GroupLayout并非合适选择,却没说明更优的布局方案。


第一款应用代码

public static void main(final String[] args) {
       SwingUtilities.invokeLater(Mvp::createGui);
    }

    private static void createGui() {
        final JFrame frame = new JFrame("Page labels app");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        final JPanel panel = new JPanel(new GridLayout(2, 1));
        final JPanel tablePanel = createTablePanel();
        panel.add(tablePanel);

        frame.add(panel, BorderLayout.CENTER);

        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private static JPanel createTablePanel() {
        final PageLabelsTable table = new PageLabelsTable();
        final JScrollPane scrollPane = new JScrollPane(table);
        scrollPane.setPreferredSize(new Dimension(400, 120));
        final JPanel tablePanel = new JPanel();
        tablePanel.add(scrollPane);
        tablePanel.setBorder(BorderFactory.createTitledBorder("Page styles"));
        return tablePanel;
    }

public class PageLabelsTable extends JTable {

    private final DefaultTableModel tableModel;

    public PageLabelsTable() {

        tableModel = new DefaultTableModel();

        tableModel.addColumn("Style");
        tableModel.addColumn("Prefix");
        tableModel.addColumn("From");
        tableModel.addColumn("To");

        tableModel.addRow(
                new String[]{"Table A 00", "Table A 01", "Table A 02", "Table A 03"});

        tableModel.addRow(
                new String[]{"Table A 10", "Table A 11", "Table A 12", "Table A 13"});

        setModel(tableModel);

        Toolkit.getDefaultToolkit().addAWTEventListener(event -> {
            if (event.getID() == MouseEvent.MOUSE_CLICKED) {
                final MouseEvent mouseEvent = (MouseEvent) event;
                final int row = rowAtPoint(mouseEvent.getPoint());
                if (row == -1) {
                    clearSelection();
                }
            }
        }, AWTEvent.MOUSE_EVENT_MASK);

        getTableHeader().setReorderingAllowed(false);
        setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
        setDragEnabled(true);
    }
}

第二款应用代码

public void createUI() {

      initUI();

      final JFrame frame = new JFrame(APP_NAME);
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.setResizable(false);

      closeOnEscape(frame);
      frame.getRootPane().setDefaultButton(fixButton);

      frame.setContentPane(ui);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setMinimumSize(frame.getSize());

      frame.setVisible(true);
   }

   private void closeOnEscape(final JFrame frame) {
      // close on ESCAPE
      frame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
          .put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "Cancel");

      frame.getRootPane().getActionMap().put("Cancel", disposeFrame(frame));
   }

   private AbstractAction disposeFrame(final JFrame frame) {
      return new AbstractAction() {
         @Override
         public void actionPerformed(final ActionEvent e) {
            frame.dispose();
         }
      };
   }

   private JComponent getTwoColumnLayout(final JLabel[] labels, final JComponent[] fields) {

      if ( labels.length != fields.length ) {
         throw new IllegalArgumentException(
             "%d labels supplied for %d fields!".formatted(labels.length, fields.length));
      }
      final JComponent panel = new JPanel();
      final GroupLayout layout = new GroupLayout(panel);
      panel.setLayout(layout);
      // Turn on automatically adding gaps between components
      layout.setAutoCreateGaps(true);
      // Create a sequential group for the horizontal axis.
      final GroupLayout.SequentialGroup hGroup = layout.createSequentialGroup();
      final GroupLayout.Group yLabelGroup = layout.createParallelGroup(
          GroupLayout.Alignment.TRAILING);
      hGroup.addGroup(yLabelGroup);
      final GroupLayout.Group yFieldGroup = layout.createParallelGroup();
      hGroup.addGroup(yFieldGroup);
      layout.setHorizontalGroup(hGroup);
      // Create a sequential group for the vertical axis.
      final GroupLayout.SequentialGroup vGroup = layout.createSequentialGroup();
      layout.setVerticalGroup(vGroup);

      // add the components to the groups
      for (JLabel label : labels) {
         yLabelGroup.addComponent(label);
      }
      for (Component field : fields) {
         yFieldGroup.addComponent(field, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE);
      }
      for (int i = 0; i < labels.length; i++) {
         vGroup.addGroup(layout.createParallelGroup().addComponent(labels[i])
             .addComponent(fields[i], GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE));
      }

      addMnemonics(labels, fields);

      return panel;
   }

   private void addMnemonics(final JLabel[] labels, final JComponent[] fields) {
      final Map<Character, Character> map = new HashMap<>();
      for (int i = 0; i < labels.length; i++) {
         labels[i].setLabelFor(fields[i]);
         final String lowerCase = labels[i].getText().toLowerCase();
         for (int j = 0; j < lowerCase.length(); j++) {
            final char ch = lowerCase.charAt(j);
            if ( Character.isLetterOrDigit(ch) && map.get(ch) == null ) {
               map.put(ch, ch);
               labels[i].setDisplayedMnemonic(ch);
               break;
            }
         }
      }
   }

   /**
    * Provides a JPanel with two columns (labels & fields) laid out using GroupLayout. The arrays
    * must be of equal size.
    *
    * @param labelStrings Strings that will be used for labels.
    * @param fields       The corresponding fields.
    * @return JComponent A JPanel with two columns of the components provided.
    */
   private JComponent getTwoColumnLayout(final String[] labelStrings, final JComponent[] fields) {
      final JLabel[] labels = new JLabel[labelStrings.length];
      for (int i = 0; i < labels.length; i++) {
         labels[i] = new JLabel(labelStrings[i]);
      }
      return getTwoColumnLayout(labels, fields);
   }


   private void initUI() {
      if ( ui != null ) {
         return;
      }
      ui = new JPanel(new BorderLayout(4, 4));
      ui.setBorder(new EmptyBorder(4, 4, 4, 4));

      // Here is our control.  This puts a titled border around it,
      // instead of using a label in the PAGE_START
      final JPanel jPanel = new JPanel(new BorderLayout());
      ui.add(jPanel);

      final JPanel actionPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 15, 15));
      jPanel.add(actionPanel, BorderLayout.PAGE_END);

      this.fixButton = new JButton("Fix");
      this.resetButton = new JButton("Reset");
      this.cancelButton = new JButton("Cancel");

      Stream.of(fixButton, resetButton, cancelButton).forEach(actionPanel::add);

      // Use GroupLayout for the label/cotrnl combos.
      // make the arrays for the factory method
      final String[] labels = { "Page label style", "Start page", "Remove bookmarks" };
      final String[] ccString = LabelStyle.getAllStyles();

      final JPanel checkBoxPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
      checkBoxPanel.add(new JCheckBox("", false));

      final JComponent[] controls = { new JComboBox<>(ccString), new JTextFieldNumeric(5),
          checkBoxPanel };

      jPanel.add(getTwoColumnLayout(labels, controls));

      // throw in a few borders for white space
      final Border insideBorder = new CompoundBorder(new EmptyBorder(10, 10, 5, 10),
          new TitledBorder(APP_NAME));
      final Border border = new CompoundBorder(insideBorder, new EmptyBorder(10, 10, 5, 10));
      jPanel.setBorder(border);
   }

内容的提问来源于stack exchange,提问作者menteith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 20:14:58