简体   繁体   中英

Switching JPanel in JFrame from inside the JPanel

I'm trying to build a dynamic application based on buttons that switch the main Panel of a JFrame (which is the top content of my application) from inside the created panel.

The question is more related to a design question rather than a development question. I'm not sure of my design, but i'll try to explain it.

I have A JFrame representing my application which contains a JTabbedPane (and multiples Tabs in it). Each tab contains a default JPanel, and inside that JPanel, i'm calling a controller which is rendering my View (I'm trying to use a MVC Pattern).

But from the so called View, I have buttons which have to switch the content of the JPanel (Jpanel contained in the JTabbedPane). And I'm searching the best way to switch the View, without breaking the standard rules of OOP.

Schematically :

JFrame
    JTabbedPane
        JPanel
            View1
                Button (pointing somehow to View2)
        JPanel
            View3
                 Button (pointing somehow to View4)

When I click on the button from view 1, I would like to have this :

JFrame
    JTabbedPane
        JPanel
            View2
                ...
        JPanel
            View3
                 Button (pointing somehow to View4)

And, once the View 2 is loaded, if I go to the View3 through the JTabbedPane and click the View3.button, I would like to have something like this :

JFrame
    JTabbedPane
        JPanel
            View2
                ...
        JPanel
            View4
                 ...

As I said it's more a design problem. Is my "design" good enough to not have to give to each component a reference of the JFrame ? How can I perform that ?

I hope there are not so much errors in my text, English is not my native language. Moreover, any corrections on my writing skills in english are welcome.

Thank you.

I'd say your JTabbedPane is the class interested in panels - as it's the JTabbedPane which will get it's contents switched.

So I'd say extend JTabbedPane to ?TabbedPane (where ? stands for 'My' or whatever the naming convention in your project is), and make it extend ActionListener, like this:

public class MyTabbedPane extends JTabbedPane implements ActionListener {
    ...
    public void actionPerformed(ActionEvent aev) {
        // replace panels
        revalidate();
        repaint();
    }
}

Then register the tabbed pane as an action listener where needed (the buttons, probably).

If there's more than one panel to switch to, you'll need some more code to pass the state. You could write your own listener:

public class PanelSwitchActionListener {
    public void panelSwitchRequested(...);
}

Then pass Enum denoting which panel to switch to, or maybe even the panel itself in the (...) part of panelSwitchRequested() method. Then add an Action(Listener) to the buttons and make them fire panelSwitchRequested() against registered PanelSwitchActionListener (which will hopefully be your JTabbedPane).

I'd try and fall back on a model. The model would maintain a list of views and a means by which, given a view reference, it could return the next view (ie model.getNextView(view) ).

This model could be passed to your controller (in this I'd say a custom JTabbedPane as mention by pafau) that could construct all the tabs as required. This way you decouple of the navigation mechanism from the view and delegate the logic to the model instead.

Personally, I would reconsider a design that uses both tabbed panes and switches between Views. Usually tis either/or with tabbed panes being preferred.

However, if you still need it that way, try to think about your views differently. I think the JPanels are actually the Views. If you attach a Controller to each View and a Model to each Controller, you'll be able to switch between them without putting too much logic in your Views or your Controllers, but still decoupling your Views from your Models. I put a rough example together that uses CardLayout and a Null Object , but is otherwise fairly straightforward. And of course, all the classes should be renamed to something that fits your project.

View.java

public class View extends JPanel {

    private CardLayout layout;


    public View(Controller controller, JComponent... subviews) {
        layout = new CardLayout();
        setLayout(layout);

        for (int index = 0; index < subviews.length; ++index) {
            JButton changeButton = new JButton("Change");
            changeButton.addActionListener(controller);
            subviews[index].add(changeButton);
            add(subviews[index], "View" + index);
        }
    }

    public void setSubview(int index) {
        layout.show(this, "View" + index);
    }

}

NullView.java

public class NullView extends View {

    public NullView() {
        super(null);
    }

    @Override
    public void setSubview(int index) {
        // do nothing
    }

}

Controller.java

public class Controller implements ActionListener {

    private Model model;

    private View view;

    public Controller(Model model) {
        this.model = model;
        this.view = new NullView();
    }

    public void setView(View view) {
        this.view = view;
    }

    public void actionPerformed(ActionEvent e) {
        model.nextIndex();
        view.setSubview(model.getCurIndex());
    }

}

Model.java

public class Model {

    private int nViews;

    private int curIndex;

    public Model(int nViews) {
        if (nViews <= 0) nViews = 1;
        this.nViews = nViews;
    }

    public void nextIndex() {
        curIndex = (curIndex + 1) % nViews;
    }

    public int getCurIndex() {
        return curIndex;
    }

 }

In your content pane:

 Controller controller1 = new Controller(new Model(2));

 View view1 = new View(controller1, subview1, subview2);
 controller1.setView(view1);

 Controller controller2 = new Controller(new Model(3));

 View view2 = new View(controller2, subview3, subview4, subview5);
 controller2.setView(view2);

 JTabbedPane tabbedPane = new JTabbedPane();
 tabbedPane.addTab("Tab1", view1);
 tabbedPane.addTab("Tab2", view2);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM