1
votes

I am trying to implement a GUI in Java Swing (I am new to Swing). I have a parent panel that holds 2 panels. A left panel and a right panel. The left panel has a JComboBox dropdown menu. The right panel is a CardLayout with 7 cards. I want to change the card displayed in the right panel based on the choice in the JComboBox in the left panel. All 3 panels are separate classes: LeftPanel.java, RightPanel.java, and ParentPanel.java. I am having a hard time finding a place to put the action listeners for this action. The LeftPanel can't see the CardLayout of the RightPanel and the ParentPanel isn't able to access the CardLayout of the child RightPanel either. I saw some posts about accessing CardLayout of another JPanel but none of the approaches have worked for me so far. Is there a flaw in my design? Or is it possible to achieve this?

EDIT Thanks for the advice so far. Given below is my MCVE. Please note that each class is in its own (.java) file. I did that instead of putting everything in the Frame class just for ease of maintenance. I had everything in one class previously and it worked fine but it became one long file with 2000+ lines of code and 20+ panels.

//Class MainFrame containing the Main method:

package tempgui; public class MainFrame extends JFrame{

JFrame Frame1;

public static void main(String[] args){

    new MainFrame();
}

public MainFrame(){

    Frame1 = new JFrame();
    Frame1.setDefaultCloseOperation(EXIT_ON_CLOSE);

    Frame1.getContentPane().add(new ParentPanel(), BorderLayout.CENTER);        

    Frame1.setSize(800, 600);
    Frame1.setLocationRelativeTo(null);
    Frame1.pack();

    Frame1.setVisible(true);
}

}

//Class ParentPanel: public class ParentPanel extends JPanel{

private JPanel ParentPanel;
private LeftPanel LP;
private RightPanel RP;

public ParentPanel(){

    ParentPanel = new JPanel();
    LP = new LeftPanel();
    RP = new RightPanel();

    ParentPanel.setLayout(new GridLayout(1,2));

    ParentPanel.add(LP);
    ParentPanel.add(RP);

    add(ParentPanel);
}

}

//Class LeftPanel: public class LeftPanel extends JPanel{

private JPanel LeftPanel;
private JComboBox J1;

public LeftPanel(){

    LeftPanel = new JPanel();

    String[] Arr = {"RP1","RP2"};

    J1 = new JComboBox(Arr);

    LeftPanel.add(J1);

    add(LeftPanel);
}

}

//Class RightPanel: public class RightPanel extends JPanel{

private JPanel RightPanel;
private RP1Panel RP1;
private RP2Panel RP2;
private CardLayout C1;

public RightPanel(){

    RightPanel = new JPanel();
    RP1 = new RP1Panel();
    RP2 = new RP2Panel();

    C1 = new CardLayout();

    RightPanel.setLayout(C1);

    RightPanel.add(RP1, "RP1");
    RightPanel.add(RP2, "RP2");
    C1.show(RightPanel, "RP1");

    add(RightPanel);
}

}

//Class RP1Panel: public class RP1Panel extends JPanel{

private JPanel RP1;
private JLabel JRP1;

public RP1Panel(){

    RP1 = new JPanel();
    JRP1 = new JLabel("RP1 Panel");
    RP1.add(JRP1);
    add(RP1);
}

}

//Class RP2Panel: public class RP2Panel extends JPanel{

private JPanel RP2;
private JLabel JRP2;

public RP2Panel(){

    RP2 = new JPanel();
    JRP2 = new JLabel("RP2 Panel");
    RP2.add(JRP2);
    add(RP2);
}

}

1
"Or is it possible to achieve this?" -- yes, most definitely. "Is there a flaw in my design?" -- without pertinent code, preferably a valid minimal reproducible example, it's impossible to say where your problem is. Again, consider creating and posting an MCVE, a small program, small enough to be posted in your question as code-formatted text, one that compiles and runs, and that demonstrates your problem for us. It's not your whole program, it doesn't have all it's functionality, but again it runs for us, and it demonstrates the problem for us.Hovercraft Full Of Eels
"All 3 panels are separate classes" Step 1 to this conundrum would probably be "don't extend component classes unnecessarily". Can you explain the case for extending panels here?Andrew Thompson

1 Answers

2
votes

I would try to give my classes methods that allow other classes to extract "state" information from them, such as the state of the combobox, and allow other classes to mutate them, such as allowing listeners to be added to the combobox. For instance:

// Class LeftPanel:
class LeftPanel extends JPanel {
    private JPanel leftPanel;
    private JComboBox<String> comboBox; //!!

    // !!
    public LeftPanel(String[] comboTexts) {
        leftPanel = new JPanel();
        comboBox = new JComboBox<>(comboTexts); // !!
        leftPanel.add(comboBox);
        add(leftPanel);
    }

    // !!
    public String getComboSelection() {
        return comboBox.getSelectedItem().toString();
    }

    // !!
    public void comboAddActionListener(ActionListener listener) {
        comboBox.addActionListener(listener);
    }
}

Then other classes can listen for changes to the combo box, and extract the selection when needed. The right panel would likewise have a method to allow change of the "card" JPanel that it displays. Something like:

// Class RightPanel:
class RightPanel extends JPanel {
    private JPanel rightPanel;
    private RP1Panel rightPanel1;
    private RP2Panel rightPanel2;
    private CardLayout cardLayout;

    public RightPanel() {
        rightPanel = new JPanel();
        rightPanel1 = new RP1Panel();
        rightPanel2 = new RP2Panel();
        cardLayout = new CardLayout();
        rightPanel.setLayout(cardLayout);
        rightPanel.add(rightPanel1, RP1Panel.NAME); //!!
        rightPanel.add(rightPanel2, RP2Panel.NAME);  // !!
        cardLayout.show(rightPanel, RP1Panel.NAME); // !!
        add(rightPanel);
    }

    // !! 
    public void showCard(String name) {
        cardLayout.show(rightPanel, name);
    }
}

And they could be tied together in the main:

// Class ParentPanel:
class ParentPanel extends JPanel {
    private JPanel ParentPanel;
    private LeftPanel leftPanel;
    private RightPanel rightPanel;

    public ParentPanel() {
        ParentPanel = new JPanel();
        leftPanel = new LeftPanel(new String[] {RP1Panel.NAME, RP2Panel.NAME});
        rightPanel = new RightPanel();
        ParentPanel.setLayout(new GridLayout(1, 2));
        ParentPanel.add(leftPanel);
        ParentPanel.add(rightPanel);
        add(ParentPanel);

        // !!
        leftPanel.comboAddActionListener(e -> {
            String selection = leftPanel.getComboSelection();
            rightPanel.showCard(selection);
        });
    }
}

The whole MCVE could look like:

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.GridLayout;
import java.awt.event.ActionListener;

import javax.swing.*;

public class FooGui {
    public static void main(String[] args) {
        new MainFrame();
    }
}

class MainFrame extends JFrame {
    JFrame Frame1;

    public MainFrame() {
        Frame1 = new JFrame();
        Frame1.setDefaultCloseOperation(EXIT_ON_CLOSE);
        Frame1.getContentPane().add(new ParentPanel(), BorderLayout.CENTER);
        Frame1.setSize(800, 600);
        Frame1.setLocationRelativeTo(null);
        Frame1.pack();
        Frame1.setVisible(true);
    }
}

// Class ParentPanel:
class ParentPanel extends JPanel {
    private JPanel ParentPanel;
    private LeftPanel leftPanel;
    private RightPanel rightPanel;

    public ParentPanel() {
        ParentPanel = new JPanel();
        leftPanel = new LeftPanel(new String[] {RP1Panel.NAME, RP2Panel.NAME});
        rightPanel = new RightPanel();
        ParentPanel.setLayout(new GridLayout(1, 2));
        ParentPanel.add(leftPanel);
        ParentPanel.add(rightPanel);
        add(ParentPanel);

        // !!
        leftPanel.comboAddActionListener(e -> {
            String selection = leftPanel.getComboSelection();
            rightPanel.showCard(selection);
        });
    }
}

// Class LeftPanel:
class LeftPanel extends JPanel {
    private JPanel leftPanel;
    private JComboBox<String> comboBox; //!!

    // !!
    public LeftPanel(String[] comboTexts) {
        leftPanel = new JPanel();
        comboBox = new JComboBox<>(comboTexts); // !!
        leftPanel.add(comboBox);
        add(leftPanel);
    }

    // !!
    public String getComboSelection() {
        return comboBox.getSelectedItem().toString();
    }

    // !!
    public void comboAddActionListener(ActionListener listener) {
        comboBox.addActionListener(listener);
    }
}

// Class RightPanel:
class RightPanel extends JPanel {
    private JPanel rightPanel;
    private RP1Panel rightPanel1;
    private RP2Panel rightPanel2;
    private CardLayout cardLayout;

    public RightPanel() {
        rightPanel = new JPanel();
        rightPanel1 = new RP1Panel();
        rightPanel2 = new RP2Panel();
        cardLayout = new CardLayout();
        rightPanel.setLayout(cardLayout);
        rightPanel.add(rightPanel1, RP1Panel.NAME); //!!
        rightPanel.add(rightPanel2, RP2Panel.NAME);  // !!
        cardLayout.show(rightPanel, RP1Panel.NAME); // !!
        add(rightPanel);
    }

    // !! 
    public void showCard(String name) {
        cardLayout.show(rightPanel, name);
    }
}

// Class RP1Panel:
class RP1Panel extends JPanel {
    // !!
    public static final String NAME = "right panel 1";
    private JPanel RP1;
    private JLabel JRP1;

    public RP1Panel() {
        setName(NAME);
        RP1 = new JPanel();
        JRP1 = new JLabel("RP1 Panel");
        RP1.add(JRP1);
        add(RP1);
    }
}

// Class RP2Panel:
class RP2Panel extends JPanel {
    // !!
    public static final String NAME = "right panel 2";
    private JPanel RP2;
    private JLabel JRP2;

    public RP2Panel() {
        setName(NAME);
        RP2 = new JPanel();
        JRP2 = new JLabel("RP2 Panel");
        RP2.add(JRP2);
        add(RP2);
    }
}