【问题标题】:Swing's GroupLayout and setContentPane - losing Components?Swing 的 GroupLayout 和 setContentPane - 丢失组件?
【发布时间】:2012-05-02 09:30:31
【问题描述】:

经过实验,在我看来,Swing 的 GroupLayout 往往会丢失打算在我的 GUI 中重复使用的组件。

但我在文档中没有看到任何明确说明此一次性使用规则的内容。这让我怀疑我是否犯了一个错误,或者我是一个可怜的读者。

例如,我用 JButton("Foo") 的 GroupLayout 制作了一个 JPanel。然后我用同一个 JButton 的 GroupLayout 制作另一个 JPanel,重命名为“Bar”。

如果我使用 JFrame.setContentPane 从第二个 JPanel 切换回第一个 JPanel,我会丢失第一个 JPanel 中的 JButton。

谁能解释为什么它会丢失组件,进一步,谁能提供一种方法来克服丢失组件的趋势?

这是一个完整的 SSCCE 演示该问题:

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class GroupLayoutTest {

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            deployGroupLayoutTest();
        }
    });
}

static JPanel firstPanel;
static JButton jbtnActionLog;
static JFrame systemFrame;

public static void deployGroupLayoutTest() {
    systemFrame = new JFrame("Group Layout Test");
    systemFrame.setSize(300, 300);

    firstPanel = new JPanel();

    JMenuBar jmbSystem = new JMenuBar();

    JMenu jmuAction = new JMenu("Action");

    JMenuItem jmiActionLog = new JMenuItem("Login");
    jmuAction.add(jmiActionLog);

    jmbSystem.add(jmuAction);

    jbtnActionLog = new JButton("Login");
    jbtnActionLog.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            setContentPaneToSecondPanel();
        }
    });

    systemFrame.setJMenuBar(jmbSystem);

    GroupLayout gl = new GroupLayout(firstPanel);
    firstPanel.setLayout(gl);
    gl.setAutoCreateContainerGaps(true);
    gl.setAutoCreateGaps(true);

    GroupLayout.ParallelGroup hGroup = gl.createParallelGroup(GroupLayout.Alignment.CENTER);
    hGroup
            .addComponent(jbtnActionLog);

    gl.setHorizontalGroup(hGroup);

    GroupLayout.SequentialGroup vGroup = gl.createSequentialGroup();
    vGroup
            .addComponent(jbtnActionLog);
    gl.setVerticalGroup(vGroup);

    systemFrame.getContentPane().add(firstPanel);
    systemFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    systemFrame.setLocationByPlatform(true);
    systemFrame.setVisible(true);

}

public static void setContentPaneToSecondPanel() {
    jbtnActionLog.setText("Logout");
    ActionListener[] listenerList = jbtnActionLog.getActionListeners();
    jbtnActionLog.removeActionListener(listenerList[0]);
    jbtnActionLog.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            systemFrame.setContentPane(firstPanel);
            systemFrame.revalidate();
        }
    });

    JPanel secondPanel = new JPanel();

    GroupLayout gl = new GroupLayout(secondPanel);
    secondPanel.setLayout(gl);
    gl.setAutoCreateContainerGaps(true);
    gl.setAutoCreateGaps(true);

    GroupLayout.ParallelGroup hGroup = gl.createParallelGroup(GroupLayout.Alignment.CENTER);
    hGroup
            .addComponent(jbtnActionLog);

    gl.setHorizontalGroup(hGroup);

    GroupLayout.SequentialGroup vGroup = gl.createSequentialGroup();
    vGroup
            .addComponent(jbtnActionLog);
    gl.setVerticalGroup(vGroup);

    systemFrame.setContentPane(secondPanel);
    systemFrame.revalidate();
}

}

【问题讨论】:

    标签: java swing grouplayout contentpane


    【解决方案1】:

    我没有浏览您的所有代码,但根本不可能将单个 Swing 组件添加到多个父级。每个组件只能出现在 Swing 层次结构中的一个位置。所以代码

    JPanel firstPanel = ...;
    JPanel secondPanel = ...;
    JButton button = ...;
    firstPanel.add( button );
    secondPanel.add( button );
    

    将导致button 仅包含在其中一个面板中,而不包含在两个面板中。这与GroupLayout无关。

    相关的SO question 包含指向Swing tutorial 的链接,对此进行了解释:

    每个 GUI 组件只能包含一次。如果一个组件已经在一个容器中,并且您尝试将其添加到另一个容器中,则该组件将从第一个容器中删除,然后添加到第二个容器中

    【讨论】:

    • 啊哈!感谢您解释这个问题。我想问题的答案是生成新的组件,但使用相同的 Action 或 ActionListener ... +1 以获得清晰而有启发性的答案。
    猜你喜欢
    • 2012-01-19
    • 2014-05-15
    • 2011-07-17
    • 2015-04-24
    • 2011-06-09
    • 2012-04-23
    • 1970-01-01
    • 2011-02-09
    • 1970-01-01
    相关资源
    最近更新 更多