简体   繁体   English

从JPanel内部切换JFrame中的JPanel

[英]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. 我正在尝试基于按钮创建动态应用程序,这些按钮可从创建的面板内部切换JFrame的主面板(这是应用程序的顶部内容)。

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). 我有一个JFrame代表我的应用程序,其中包含一个JTabbedPane(和其中的多个Tabs)。 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). 每个选项卡都包含一个默认的JPanel,并且在该JPanel中,我正在调用呈现我的View的控制器(我正在尝试使用MVC模式)。

But from the so called View, I have buttons which have to switch the content of the JPanel (Jpanel contained in the JTabbedPane). 但是从所谓的View中,我有一些按钮,这些按钮必须切换JPanel的内容(包含在JTabbedPane中的Jpanel)。 And I'm searching the best way to switch the View, without breaking the standard rules of OOP. 而且我正在寻找切换视图的最佳方法,同时又不违反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 : 当我从视图1中单击按钮时,我想要这样:

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 : 并且,一旦加载了View 2,如果我通过JTabbedPane转到View3并单击View3.button,我想拥有以下内容:

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 ? 我的“设计”是否足够好,不必为每个组件提供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. 我想说您的JTabbedPane是对面板感兴趣的类-因为它是JTabbedPane,它将切换其内容。

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: 因此,我想将JTabbedPane扩展到?TabbedPane(其中?代表“我的”或项目中的任何命名约定),并使其扩展ActionListener,如下所示:

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. 然后,传递Enum表示要切换到哪个面板,或者甚至将面板本身放在panelSwitchRequested()方法的(...)部分中。 Then add an Action(Listener) to the buttons and make them fire panelSwitchRequested() against registered PanelSwitchActionListener (which will hopefully be your JTabbedPane). 然后在按钮上添加一个Action(Listener),并使它们针对已注册的PanelSwitchActionListener(希望是您的JTabbedPane)触发panelSwitchRequested()。

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) ). 该模型将维护一个视图列表,以及一个给定视图引用的方法,它可以返回下一个视图(即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. 该模型可以传递给您的控制器(在此我要说一个自定义的JTabbedPane,如pafau所述),它可以根据需要构造所有选项卡。 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. 我认为JPanels实际上是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. 我把使用CardLayoutNull Object的一个粗略示例放在一起,但否则相当简单。 And of course, all the classes should be renamed to something that fits your project. 当然,所有类都应重命名为适合您的项目的名称。

View.java 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 NullView.java

public class NullView extends View {

    public NullView() {
        super(null);
    }

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

}

Controller.java 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 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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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