0

In my application, I have several custom JPanels added to a JTabbedPane. A single JPanel offers a piece of functionality, I've added them to JTabbedPane so that the user can switch between modules easily.

All of those custom JPanels operate on the same set of data, meaning if one of the modules has to change something in the data (for instance, a List), all other panels should be aware of that change and react accordingly.

However, with JTabbedPane, you first need to instantiate those JPanels to add them to JTabbedPane - and you do it once.

I have one problem - suppose user adds something to the collection in panel A (which is shared by all those panels) and switches to panel B. What should happen in this case? How is B supposed to know that something has been added to that collection?

My idea was to simply detect a tab switch event, and call the method of B to take the new data into account. But I feel this is not how it should be done.

What could you suggest?

user4205580
  • 564
  • 5
  • 25
  • *"In my application, I have several custom JPanels.."* Why are they 'custom' & by custom, do you mean `extends JPanel`? – Andrew Thompson May 29 '16 at 19:42
  • *"the same set of data"* That suggests keeping a single model for the (supposedly related) data, which is represented in the various panels. – Andrew Thompson May 29 '16 at 19:43
  • @AndrewThompson yes, I mean they extend JPanel. Having a model is one thing, how to use it properly in this case is the question. For instance, my JPanel may look completely different (different buttons, etc.), depending on current data. – user4205580 May 29 '16 at 19:52
  • @AndrewThompson Let's talk about a simple JComboBox. I initialize it by passing a DefaultComboBoxModel to it + a custom renderer. The DefaultComboBoxModel contains the collection from my 'model'. What if the collection is modified? I need to update the combo box model manually, right? – user4205580 May 29 '16 at 20:24
  • *"I mean they extend JPanel."* ***Why?*** – Andrew Thompson May 29 '16 at 20:25
  • @AndrewThompson Because this is what others recommend to do. If my panel is supposed to provide some kind of functionality and is able to 'work' on its own, it makes sense to subclass JPanel. – user4205580 May 29 '16 at 20:28
  • *"Because this is what others recommend.."* Who, exactly? I'd advise [composition over inheritance](https://en.wikipedia.org/wiki/Composition_over_inheritance).. – Andrew Thompson May 29 '16 at 20:33
  • @AndrewThompson you could think of those panels as panels allowing to perform some action X, so they are panels. We have is-a relationship so using inheritance is not totally wrong here. How does it affect the problem I've described? If I didn't subclass JPanel, I could simply remove everything add the necessary components to the JPanel in JTabbedPane, every time the user switches tabs. Is it any close to what you'd suggest? Actually I could do the same thing atm by adding my custom JPanels to normal JPanels (added to JTabbedPane), once someone clicks another tab. – user4205580 May 29 '16 at 20:42

1 Answers1

2

In the example below, each panel in the tabbed pane has its own JComboBox that listens to a common ComboBoxModel. When the common model is updated, by clicking Update, each listening JComboBox sees the change.

I never need any two combo boxes to share a model. My panels contain completely different JComponent instances, but the look and data those components display depend on several collections common to all of those panels.

You may be able to leverage the observer pattern, examined here. The exact details depend on your use case, but the PropertyChangeListener examples are worth studying.

image

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.util.Date;
import javax.swing.AbstractAction;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;

/**
 * @see https://stackoverflow.com/a/37514928/230513
 * @see https://stackoverflow.com/questions/8752037
 * @see https://stackoverflow.com/a/37222598/230513
 */
public class TabTest {

    private static final int N = 5;
    private final JTabbedPane pane = new JTabbedPane();
    private final DefaultComboBoxModel model = new DefaultComboBoxModel(
        new String[]{"Alpher", "Bethe", "Gamow", "Dirac", "Einstein"});

    public TabTest() {
        for (int i = 0; i < N; i++) {
            Color color = Color.getHSBColor((float) i / N, 1, 1);
            pane.add("Tab " + String.valueOf(i), new TabContent(i, color));
        }
    }

    private class TabContent extends JPanel {

        private TabContent(int i, Color color) {
            setOpaque(true);
            setBackground(color);
            add(new JComboBox(model));
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(320, 240);
        }
    }

    private void display() {
        JFrame f = new JFrame("TabColors");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(pane);
        JPanel p = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        p.add(new JButton(new AbstractAction("Update") {
            @Override
            public void actionPerformed(ActionEvent e) {
                model.addElement(new Date());
            }
        }));
        f.add(p, BorderLayout.SOUTH);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new TabTest().display();
            }
        });
    }
}
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • The thing is I never need any two combo boxes to share a model. My panels contain completely different JComponents, but the look and data those components display depend on several collections common to all of those panels. Once one panel modifes something in any of these collection, other panels should be aware of the change and should modify their appearance or data they display. – user4205580 May 29 '16 at 21:13
  • 1
    @user4205580: You may not need the same exact set up as found here, but you sure need the same concept -- that both views can and should share the same model. Use this concept and apply it to your set up and code, and you'll solve your problem. And please up-vote this answer as well. – Hovercraft Full Of Eels May 29 '16 at 21:44
  • I've elaborated above; see especially @Hovercraft Full Of Eels' [example](http://stackoverflow.com/a/5533581/230513); for additional guidance, please edit your question to include a [mcve], perhaps one based on the example above, that shows your current approach. – trashgod May 29 '16 at 23:09