1

I am trying to make an application, but currently a bit stuck on how to neatly structure my code.

For simplicity, suppose i want a JFrame that contains:

  1. A JPanel which contains a JComboBox in which a user can select a shape (square, circle etc.).
  2. A separate JPanel that visually displays the selected shape in the JComboBox.

So I have the following code:

public class Frame extends JFrame {

    Frame() {
        ComboBoxPanel comboBoxPanel = new ComboBoxPanel();
        ShapePanel shapePanel = new ShapePanel();

        this.getContentPane().add(comboBoxPanel, BorderLayout.WEST);
        this.getContentPane().add(shapePanel, BorderLayout.CENTER);

        this.setResizable(true);
        this.pack();
        this.setVisible(true);
    }

    public static void main(String[] args) {
        new Frame();
    }
}

ComboBoxPanel:

public class ComboBoxPanel extends JPanel {

    private JComboBox<Shape> comboBox;

    ComboBoxPanel() {
        comboBox = new JComboBox<Shape>(Shape.SHAPES);
        this.add(comboBox);

        comboBox.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    // Here I want to repaint the shapePanel
                }
            }
        });
    }
}

Finally, ShapePanel will look something like:

public class ShapePanel extends JPanel {
    @Override
    public void paintComponent(Graphics g) {
        // Get selected Shape from JComboBox and draw it
    }
}

In short, how can I let these two same-level-components interact with each other in a neat way? I have thought of some solutions but they look really dirty. Any thoughts are welcome.

Thanks.

2 Answers2

2

If both your ComboBoxPanel and ShapePanel resides in the same JFrame, they shall be to "see" one another. From there, you can just use the getters and setters from both classes to access each others' properties.

If you are talking about unrelated classes, you can always adopt a design pattern, such as the Observer pattern where the classes signs a contract and expose the interested behaviour via a method.

I have wrote a detailed example here using Observer pattern: Updating Change to another class


If you are interested to separate your User Interface and logic implementation. MVC is another viable option. Your Model will only contains your logic and data and your View only contain your UI.

Model and View do not need to know the existence of each other. You will use a Controller which links both the View and Model. This way it greatly decouples your code. So one day if you decided to change your logic, the UI is unaffected.

If you decide to change your UI, the logic is unaffected as well.


It is even possible to combine both Observer pattern and MVC. After all, It depends on what you want to achieve.

Community
  • 1
  • 1
user3437460
  • 17,253
  • 15
  • 58
  • 106
0

I would suggest reading up on the observer pattern or mvc pattern. The best solution would probably be mvc. In MVC (model, view, controller) you hold the model (your data) outside of your views (the two jpanels). Then, because the two panels share the same data, it's very easy to have your display panel driven from your input panel.

  • In more concrete terms, you could hold the selected shape in an instance variable on Frame (with a getter and setter). You would then pass "this" (the constructing Frame object) to both JPanel constructors. Then, your controlling code in your combo box panel manipulates the Frame's shape object and your display code in your shape panel displays based on the Frame's shape object. – Jeremy Lautman Mar 18 '16 at 15:07
  • So if I understand correctly, for this case I'd have something like a separate Model class which contains information about the current shape. Then in the ItemListener I would update the shape in this model class, and in the paintComponent method I would extract the shape again from this model class? And would the data in the model class then be static, or should I pass the Model class instance to the both panels' constructors so they hold a reference to it? – user2443647 Mar 18 '16 at 15:09