7

我正在尝试在 java swing ui 应用程序中遵循 MVP(特别是被动视图)模式。

应用程序的基本设计提醒了一个向导控件。屏幕分为两个主要部分:

  • 一个活跃的视图。
  • 带有导航按钮的静态导航栏。

用户可以使用按钮来更改活动视图,但始终显示栏。

为这个场景建模,我有一堆不同的 screers,每个都有自己的演示者、视图接口和视图实现(使用 JPanel)。然后我有一个 Shell 演示者,使用 JFrame 查看接口和查看实现。这个想法是外壳将首先加载并始终显示,显示底部导航栏并为活动视图留出空间。shell Presenter 将允许设置当前的活动屏幕,有点像这样:

interface View {
}

class Presenter {
    View view;

    public Presenter(View view) {
        this.view = view;
    }

    public View getView() {
        return view;
    }

}

interface ShellView extends View {
    void setActiveView(View activeView);
}

class ShellPresenter extends Presenter {
    private ShellView shellView;

    public void setActivePresenter(Presenter activePresenter) { 
        shellView.setActiveView(activePresenter.getView());
    }
}

class ShellFrame implements ShellView {
    private JFrame frame;
    private JPanel activePanel;
    private JPanel navigationBar;

    public ShellFrame() {
        Container c = frame.getContentPane();
        c.add(activePanel);
        c.add(navigationBar);
    }

    public setActiveView(View activeView) {
        ???
    }
}

问题出在 setActiveView 方法中:我不知道如何将 activeView 设置为 activePanel,当 View 界面是通用的并且因此对 JPanel 一无所知时。显然我不希望我的演示者也知道 JPanels。

4

3 回答 3

1

您能否将 View 的定义修改为:

interface View {
    JComponent getContainer();
}

让每个视图都可以轻松获取视图内容?shell 不需要知道返回的是什么 JComponent 实现。

于 2010-02-10T23:40:15.333 回答
1

您的 View 界面需要提供某种方法来获取 JPanel 中可显示的内容:

interface View {
    Component getComponent();
}

然后在 ShellFrame 中(假设您使用 BorderLayout,就像我一样)您可以通过以下方式设置视图:

public setActiveView(View activeView) {
   activePanel.add(activeView.getComponent(), BorderLayout.CENTER);     
}
于 2010-02-16T21:08:39.097 回答
1

问题是您JFrame View而不是每个单独的活动子视图。现在处于活动状态的视图是一个渲染作业,因此应该由 来完成View,而不是由Presenter. 想象一下,您想换一个不同View的子视图,而不是只有一个子视图可见,它们都是可见的,但是处于活动状态的子视图具有不同的背景颜色。演示者只控制哪个是活动的,但View控制的是活动的含义。

因此,如果不破坏封装,您的任务就无法完成,因为您正在尝试做一项本质上破坏封装的工作。所以我会做这样的事情:

class PresenterManager {
    private Presenter activePresenter;
    private List<Presenter> allPresenters;

    IView view;

    PresenterManager(IView view) {
        this.view = view;
        view.subscribe(this);
    }

    void addPresenter(Presenter p) {
        allPresenters.add(p);
    }

    void setView(int index) {
        view.setView(index);
        activePresenter = allPresenters.get(index);
    }
}

class SwingView implements IView {
    List<SubView> allViews;
    SubView activeView;
    int lastIndex;

    public void setView(int index) {
        if(index != lastIndex) {
            activeView.setVisible(false);
            activeView = allViews.get(index);
            lastIndex = index;
        }
    }
}
于 2013-08-02T17:28:39.933 回答