Question

After experimentation, it appears to me that Swing's GroupLayout tends to lose Components intended for re-use across my GUI.

But I haven't seen anything in the documentation that makes this single-use rule clear. This makes me wonder if I have made a mistake, or if I am a poor reader.

For example, I make a JPanel with a GroupLayout of a JButton("Foo"). Then I make another JPanel with a GroupLayout of the same JButton renamed "Bar".

If I switch back to the first JPanel from the second JPanel with JFrame.setContentPane, I lose the JButton in the first JPanel.

Can anyone explain why it is losing Components and further, can anyone provide a way to overcome the tendency to lose Components?

Here is a complete SSCCE demonstrating the problem:

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();
}

}

Was it helpful?

Solution

I did not go through all of your code, but it is simply not possible to add a single Swing component to multiple parents. Each component can only be present in one location in the Swing hierarchy. So the code

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

will result in button only contained in one of the panels, and not in both. This has nothing to do with the GroupLayout.

A relevant SO question contains the link to the Swing tutorial explaining this:

Each GUI component can be contained only once. If a component is already in a container and you try to add it to another container, the component will be removed from the first container and then added to the second

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top