Java Swing中的控制器是什么?

我想以有意义的方式使用Swing将MVC设计应用于我的Java应用程序。 因此我的问题是,如何在Java Swing中构建控制器?

我有两个选择:

  1. 每个组件侦听器都是一个自己的类,作为控制器包的一部分
  2. 每个组件侦听器都是视图包中的匿名类,它使用控制器方法将其调用委托给一个类。

两者都有可能吗? 这是一个偏好问题,还是明确界定?

Controller构成组件接口的另一半,主要是交互的一半。 Controller负责鼠标和键盘事件。

在像JButton等Swing组件中是控制器。 并且所有侦听器类都将事件重定向到具有业务逻辑的模型

例子:

主程序

 import javax.swing.*; public class CalcMVC { //... Create model, view, and controller. They are // created once here and passed to the parts that // need them so there is only one copy of each. public static void main(String[] args) { CalcModel model = new CalcModel(); CalcView view = new CalcView(model); CalcController controller = new CalcController(model, view); view.setVisible(true); } } 

视图

 import java.awt.*; import javax.swing.*; import java.awt.event.*; class CalcView extends JFrame { //... Constants private static final String INITIAL_VALUE = "1"; //... Components private JTextField m_userInputTf = new JTextField(5); private JTextField m_totalTf = new JTextField(20); private JButton m_multiplyBtn = new JButton("Multiply"); private JButton m_clearBtn = new JButton("Clear"); private CalcModel m_model; //======================================================= constructor /** Constructor */ CalcView(CalcModel model) { //... Set up the logic m_model = model; m_model.setValue(INITIAL_VALUE); //... Initialize components m_totalTf.setText(m_model.getValue()); m_totalTf.setEditable(false); //... Layout the components. JPanel content = new JPanel(); content.setLayout(new FlowLayout()); content.add(new JLabel("Input")); content.add(m_userInputTf); content.add(m_multiplyBtn); content.add(new JLabel("Total")); content.add(m_totalTf); content.add(m_clearBtn); //... finalize layout this.setContentPane(content); this.pack(); this.setTitle("Simple Calc - MVC"); // The window closing event should probably be passed to the // Controller in a real program, but this is a short example. this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } void reset() { m_totalTf.setText(INITIAL_VALUE); } String getUserInput() { return m_userInputTf.getText(); } void setTotal(String newTotal) { m_totalTf.setText(newTotal); } void showError(String errMessage) { JOptionPane.showMessageDialog(this, errMessage); } void addMultiplyListener(ActionListener mal) { m_multiplyBtn.addActionListener(mal); } void addClearListener(ActionListener cal) { m_clearBtn.addActionListener(cal); } } 

调节器

 import java.awt.event.*; public class CalcController { //... The Controller needs to interact with both the Model and View. private CalcModel m_model; private CalcView m_view; //========================================================== constructor /** Constructor */ CalcController(CalcModel model, CalcView view) { m_model = model; m_view = view; //... Add listeners to the view. view.addMultiplyListener(new MultiplyListener()); view.addClearListener(new ClearListener()); } ////////////////////////////////////////// inner class MultiplyListener /** When a mulitplication is requested. * 1. Get the user input number from the View. * 2. Call the model to mulitply by this number. * 3. Get the result from the Model. * 4. Tell the View to display the result. * If there was an error, tell the View to display it. */ class MultiplyListener implements ActionListener { public void actionPerformed(ActionEvent e) { String userInput = ""; try { userInput = m_view.getUserInput(); m_model.multiplyBy(userInput); m_view.setTotal(m_model.getValue()); } catch (NumberFormatException nfex) { m_view.showError("Bad input: '" + userInput + "'"); } } }//end inner class MultiplyListener //////////////////////////////////////////// inner class ClearListener /** 1. Reset model. * 2. Reset View. */ class ClearListener implements ActionListener { public void actionPerformed(ActionEvent e) { m_model.reset(); m_view.reset(); } }// end inner class ClearListener } 

模型

 import java.math.BigInteger; public class CalcModel { //... Constants private static final String INITIAL_VALUE = "0"; //... Member variable defining state of calculator. private BigInteger m_total; // The total current value state. //============================================================== constructor /** Constructor */ CalcModel() { reset(); } //==================================================================== reset /** Reset to initial value. */ public void reset() { m_total = new BigInteger(INITIAL_VALUE); } //=============================================================== multiplyBy /** Multiply current total by a number. *@param operand Number (as string) to multiply total by. */ public void multiplyBy(String operand) { m_total = m_total.multiply(new BigInteger(operand)); } //================================================================= setValue /** Set the total value. *@param value New value that should be used for the calculator total. */ public void setValue(String value) { m_total = new BigInteger(value); } //================================================================= getValue /** Return current calculator total. */ public String getValue() { return m_total.toString(); } } 

Platzhirsch,

老兄,这是一个非常严重的问题……没有人会在论坛post中充分回答。 这个由Robert Eckstein (Java神之一)的MVC Java SE Application Design With MVC详细讨论了这个问题。

就个人而言,我最终使用了MVC的“变体”,我称之为MBVC(模型业务视图控制器),它实际上非常接近MVVMC … MVVM广泛用于.NET圈; 添加一个控制器对我来说很有意义,因为我有一些网络MVC经验。 我希望在我开始使用MVC-ise my app之前阅读上面的文章。 您仍然可以在Sun(现在的甲骨文)Java论坛上阅读我相当困惑的post。

干杯。 基思。

虽然Swing框架已经实现了一种forms的MVC(显式模型; JXyz和UI类=控制器和视图),但这种严格的分离很少在应用程序级别上使用,看起来很奇怪。

首先,我建议遵循以下设计:

  • 使用POJO实现客户端业务逻辑
  • 在需要的地方用自定义Swing模型包装POJO(ListModel,TableModel)
  • 使用GUI构建器来设计GUI
  • 使用Mediator模式侦听事件(自定义父JPanel侦听其子事件的事件并更新其他子项或在需要时触发自己的事件)

如果您想更进一步,请使用RCP,例如NetBeans平台(非常推荐)。

看看这个MVC架构

该视图将包含GUI设计。 视图的actionPerformed方法应标识事件,并根据事件调用ControllerInterface上的相应方法。 控制器实现将实现此ControllerInterface,并且将在此处实现视图调用的方法。 这些方法可能会以某种方式与模型相互作用。 模型本身将有一种方法来注册观察者(视图,在这种情况下;偶然地,甚至可以注册控制器)并在每次模型更改时更新观察者。 这实际上就是你如何构建你的应用程序。 有关MVC的更多详细信息,您还可以参考: 这里!

为了清楚地分离View和Controller,你可以这样做:

 public class MyView extends SomeSwingComponent { private Controller controller; public View(Controller controller) { this.controller = controller; JButton saveButton = new JButton("Save"); button.addActionListner(controller.getSaveButtonListener()); } } 

 public class MyController implements Controller { private ActionListener saveButtonListener; @Override public ActionListener getSaveButtonListener() { if (saveButtonListener == null) { saveButtonListener = new ActionListener() { // ... } } } 

现在我们可以实现不同的控制器,如果我们想要使用不同模型的视图组件,这可能很方便。 控制器是实际视图实例的策略

在大多数情况下,将侦听器定义为匿名类就足够了,因为它们通常只是在控制器实例上调用一个方法。 我通常将侦听器用作简单的调度程序 – 它们会收到通知并向另一个对象发送消息。 监听器类应该实现太多的业务逻辑,这超出了它的职责范围。

我有两个选择:

  1. 每个组件侦听器都是一个自己的类,作为控制器包的一部分
  2. 每个组件侦听器都是视图包中的匿名类,它使用控制器方法将其调用委托给一个类。 两者都有可能吗?

是的,两者都是可能的,但我更愿意编写实现所有actionListioner的Single类,并将其分配给应用程序中的所有组件。 这样,您就可以在单点跟踪应用中的所有操作。 这样,您可以使您的视图与控制器区分开来。