【问题标题】:MVC - Observer/Observable pattern in Java SwingMVC - Java Swing 中的观察者/可观察模式
【发布时间】:2012-09-02 04:13:34
【问题描述】:

我正在尝试构建一个基于 MVC 的 Swing 用户界面,并且有几个关于该主题的问题。询问我问题的最佳方式是借助一个简单的示例。

假设我们有一个带有一个 JButton 和 3 个 JTextField 的 JDialog。当按下该按钮时,我希望此 JDialog 关闭并打开另一个需要来自 3 个 JTextField 的数据。

执行此操作的简单方法(只需 sn-ps 的代码,无需过多打扰您)是:

myButton.addMouseListener(new MouseAdapter(){

    @Override
    public void mouseClicked(MouseEvent evt){
        firstFrame.setVisible(false);
        secondFrame.setData(jTextField1.getText(),jTextField2.getText(),jTextField3.getText());//just sending the data to the new window, would be this or something similar
        secondFrame.setVisible(true);
        }});

或者类似的东西。

第一个问题:如果我不使用匿名内部类但决定为我的 Listener 使用单独的类,我将如何将数据从 3 个 JTextFields 传递到我的 mouseListener 类?除了在 Listener 类中保留视图的引用之外,还有其他选择吗?

继续,给定 MVC 模式:

第二个问题:我想监听器(根据 MVC 的控制器)在不涉及模型的情况下调用另一个窗口是有意义的,我猜这是工作。但是需要从一个窗口传递到下一个窗口的数据(来自 3JTextFields 的数据)不应该通过模型吗?就像让第一个窗口将数据保存在模型中,然后当第二个窗口需要它们时从模型中请求它们。

第三个问题:我正在考虑使用 Observer/Observable 模式。在此示例中如何使用它来打开最后一个窗口?我的意思是,因为(我认为)Controller 是打开第二个窗口的类,这是否意味着 Listener 必须被 Observed 并且第二个窗口必须是 Observer 以便 Listener 会说

 notifyObservers("openSecondWindow");

然后第二个窗口会看到它并自行打开?

最后:我听说 PropertyChangeListener 也可以工作,而且有时它比 Observer/Observable 模式更受欢迎。您对此有何看法,尤其是关于我的示例。

我很困惑..

感谢您的宝贵时间。

【问题讨论】:

  • 有一个属性更改示例here
  • 我想说的是,我没有更改属性,我只是想打开一个新窗口。我想我可以用 PropertyChangeListener 来做,但是用它来做这个动作真的有意义吗?
  • 哦,我会使用CardPanel,引用here,而不是打开一个新窗口。编辑:另外,尝试专注于一个问题。
  • 我知道 CardLayout,谢谢。对于这个问题,我们只是说我选择不使用一个窗口并让一个窗口打开一个完全不同的窗口
  • 然后我会看一个对话框或完全不同的设计。顺便说一句,PropertyChangeListener 只是实现观察者模式的一种方式。其他人提到here

标签: java swing model-view-controller observer-pattern


【解决方案1】:

第一个问题

如果我不使用匿名内部类,但决定为我的 Listener 使用单独的类,我将如何将数据从 3 个 JTextField 传递到我的 mouseListener 类?

您单独的 MouseAdapter 类将有一个构造函数,您可以在其中将您需要的内容从您的 JPanel 类传递给您的 MouseAdapter 类。

这段代码用于ActionListener,但我认为总体思路将向您展示如何编写MouseAdapter 类。

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import com.ggl.project.planner.model.Planner;
import com.ggl.project.planner.model.Project;
import com.ggl.project.planner.view.CreateUpdateProjectDialog;
import com.ggl.project.planner.view.ProjectPlannerFrame;

public class CreateProjectActionListener implements ActionListener {

    protected Planner planner;

    protected Project project;

    protected ProjectPlannerFrame frame;

    public CreateProjectActionListener(ProjectPlannerFrame frame,
            Planner planner, Project project) {
        this.frame = frame;
        this.planner = planner;
        this.project = project;
    }

    @Override
    public void actionPerformed(ActionEvent event) {
        CreateUpdateProjectDialog dialog = 
                new CreateUpdateProjectDialog(frame, project, true);
        if (dialog.isOkPressed()) {
            planner.setProjectOpen(true);
        }
    }

}

第二个问题

我想监听器(根据 MVC 的控制器)在不涉及模型的情况下调用另一个窗口是有意义的,我猜这是工作。但是需要从一个窗口传递到下一个窗口的数据(来自 3JTextFields 的数据)不应该通过模型吗?就像让第一个窗口将数据保存在模型中,然后当第二个窗口需要它们时从模型中请求它们。

我不确定我是否理解您的问题。当我构建一个 GUI 时,我有一个或多个数据模型来表示来自 GUI 的值。这些数据模型的实例通过构成 GUI 的大部分组件传递。

应用程序的其余部分通过模型访问 GUI 信息。

在我作为第一个问题答案的一部分发布的 ActionListener 类中,有 2 个数据模型,ProjectPlannerProject 特定于特定项目,而 Planner 对 GUI 来说是全局的。

第三个问题

我正在考虑使用 Observer/Observable 模式。在此示例中如何使用它来打开最后一个窗口?

Swing 已经内置了侦听器模式。您可以将操作侦听器用于您自己的操作。您甚至可以将自己的侦听器类型添加到 Swing,尽管这是一个痛苦的过程。当我扩展 JPanel 以创建 JCroppingPanel 时,我添加了自己的侦听器类型。

【讨论】:

    【解决方案2】:

    我不确定 Java 的特定方面。但是谈到 OOP,让您的应用程序通过事件驱动设计解耦是非常合理的。因此,您无需直接处理组件,而是触发事件,正如您所写:notifyObservers("openSecondWindow");

    但是,您不需要通过模型层来执行此操作。相反,您应该有一个代表给定事件的 event 类,并在事件类中设置提到的字段的值。

    类似:

    exampleEvent.setProperty1('blah').setProperty2('blah2');
    notify('openSecondFrame', exampleEvent);
    

    我不久前就这个事件驱动的东西发布了一个问题:

    PHP: Am I mixing up event-driven programming with signals-aware interfaces (Signal and Slots / Observer Pattern)?

    您可能有兴趣阅读几个链接(它是 PHP,但该概念适用于 OOP)。

    因此,按照这个概念,创建一个EventHandler 组件来管理这些事件和信号是个好主意。

    但是,再次考虑到我并不精通 Java。这只是关于 OOP。

    【讨论】:

    • 谢谢,这实际上非常有用。我会尝试自己创建一些活动,看看这种方式是否更适合我。
    • 在 Java 中,考虑EventListenerList,引用here
    猜你喜欢
    • 2012-12-29
    • 1970-01-01
    • 2012-07-09
    • 2013-11-05
    • 2013-02-12
    • 2013-08-03
    • 2016-08-26
    • 2016-02-20
    • 2023-04-10
    相关资源
    最近更新 更多