任何解决方案都需要某种形式的模型-视图-控制器。这将有助于在解耦 API 的同时简化功能。
首先,我先看看How to use Actions。这些是独立的工作单元,可以轻松应用于按钮和键绑定,并为可重用的 sn-ps 代码提供基础。
例如,我们可以定义一个非常简单的Action,它简单地管理视图与控制器的交互,以方便视图的切换:
public abstract class AbstractManagerAction extends AbstractAction {
private Controller controller;
private JPanel panel;
public AbstractManagerAction(Controller manager, JPanel panel) {
this.controller = manager;
this.panel = panel;
}
@Override
public void actionPerformed(ActionEvent e) {
controller.show(panel);
}
}
Action 并不关心Controller“如何”工作,只是当它将视图传递给它时,视图将显示在屏幕上,因此控制器的底层实现发生了变化,但是,由于API建立的契约,Action不需要更改。
现在,您可以拥有一个处理创建 JDialog 的 Controller 和一个管理 JFrame 的 Controller,并根据需要将它们链接在一起。
好的,但是我听到你问这实际上如何让你的生活变得更简单?
好吧,假设您有这样的视图...
public class SomeOptionsPane extends JPanel {
public SomeOptionsPane() {
setLayout(new GridBagLayout());
add(new JLabel("Some options"));
}
}
为了在屏幕上呈现它,我们需要先定义它自己的Action...
public class SomeOptionsAction extends AbstractManagerAction {
public SomeOptionsAction(Controller controller) {
super(controller, new SomeOptionsPane());
putValue(NAME, "Some options");
}
}
这使我们可以抽象出通用功能(如上所示),但允许对视图本身进行自定义(在这种情况下,我只定义了将要显示的文本)。您还可以定义一堆其他属性,但为简洁起见,我跳过了这一步。
现在,当我想将选项添加到JMenuBar/JMenu 时,我只需要创建一个Action 的实例...
JMenu options = new JMenu("Options");
options.add(new SomeOptionsAction(controller));
简单。现在,当Action 被触发时,它将调用Controllers show 方法并将视图实例传递给它!魔法!
总体而言,您还可以考虑使用CardLayout 或JTabbedPane 来进一步改善用户体验,具体取决于用户界面的总体复杂程度。请参阅How to use CardLayout 和How to Use Tabbed Panes 了解更多详情。
而且,因为我知道在你看到它运行之前你不会满意,所以我用来测试这个想法的基本代码..
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Controller manager = new Controller() {
@Override
public void show(JPanel pane) {
frame.getContentPane().removeAll();
frame.getContentPane().add(pane);
frame.getContentPane().revalidate();
frame.getContentPane().repaint();
}
};
JMenuBar menuBar = new JMenuBar();
JMenu options = new JMenu("Options");
menuBar.add(options);
options.add(new SomeOptionsAction(manager));
options.add(new SomeOtherOptionsAction(manager));
frame.setJMenuBar(menuBar);
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface Controller {
public void show(JPanel pane);
}
public abstract class AbstractManagerAction extends AbstractAction {
private Controller controller;
private JPanel panel;
public AbstractManagerAction(Controller controller, JPanel panel) {
this.controller = controller;
this.panel = panel;
}
@Override
public void actionPerformed(ActionEvent e) {
controller.show(panel);
}
}
public class SomeOptionsAction extends AbstractManagerAction {
public SomeOptionsAction(Controller controller) {
super(controller, new SomeOptionsPane());
putValue(NAME, "Some options");
}
}
public class SomeOptionsPane extends JPanel {
public SomeOptionsPane() {
setLayout(new GridBagLayout());
add(new JLabel("Some options"));
}
}
public class SomeOtherOptionsAction extends AbstractManagerAction {
public SomeOtherOptionsAction(Controller manager) {
super(manager, new SomeOtherOptionsPane());
putValue(NAME, "Some other options");
}
}
public class SomeOtherOptionsPane extends JPanel {
public SomeOtherOptionsPane() {
setLayout(new GridBagLayout());
add(new JLabel("Some other options"));
}
}
}
现在,在我被烤之前,我知道这不是一个“传统”的 MVC,但 Swing 也不是,所以我专注于提供一个解耦的解决方案