我正在尝试在Java swing ui应用程序中遵循MVP(特别是Passive-View)模式。
该应用程序的基本设计让人想起向导控件。屏幕分为两个主要部分:
活动视图。
带有导航按钮的静态导航栏。
用户可以使用按钮来更改活动视图,但是始终显示该栏。
对此场景进行建模时,我有一堆不同的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方法中:我不确定在View接口是通用的情况下如何将activeView设置为activePanel,因此对JPanels一无所知。显然,我也不想让我的主持人也了解JPanels。
您是否曾经知道过该怎么做? 这些答案都不是特别好。 我刚刚发布了此线程:stackoverflow.com/questions/17836421/
问题是您的JFrame是View,而不是每个单独的活动子视图。当前处于活动状态的视图是渲染工作,因此应由View而不是Presenter完成。想象一下,您想换一个不同的View,而不是只看到一个子视图,而是全部可见,但是活动的那个具有不同的背景色。演示者仅控制哪个是活动的,而View控制什么是活动的。
因此,如果不破坏封装就不能完成您的任务,因为您试图做的工作本质上就是破坏封装。所以我会做这样的事情:
class PresenterManager {
private Presenter activePresenter;
private List 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 allViews;
SubView activeView;
int lastIndex;
public void setView(int index) {
if(index != lastIndex) {
activeView.setVisible(false);
activeView = allViews.get(index);
lastIndex = index;
}
}
}
您的View界面需要提供某种方式来获取可在JPanel中显示的内容:
interface View {
Component getComponent();
}
然后在ShellFrame中(假设您像我一样使用BorderLayout),可以通过以下方式设置视图:
public setActiveView(View activeView) {
activePanel.add(activeView.getComponent(), BorderLayout.CENTER);
}
您可以将View的定义修改为:
interface View {
JComponent getContainer();
}
这样每个视图都可以轻松获取视图内容? Shell不需要知道将返回什么JComponent实现。