将 MVC 与 JavaFx 一起应用

2024-03-11

我是 GUI 世界/OO 设计模式的新手,我想在我的 GUI 应用程序中使用 MVC 模式,我已经阅读了一些关于 MVC 模式的教程,模型将包含数据,视图将包含视觉元素和控制器将连接视图和模型。

我有一个包含 ListView 节点的视图,并且 ListView 将填充来自 Person 类(模型)的名称。但我对一件事有点困惑。

我想知道的是从文件加载数据是否是控制器或模型的责任?以及名称的 ObservableList:它应该存储在 Controller 还是 Model 中?


这种模式有许多不同的变体。特别是,Web 应用程序上下文中的“MVC”与胖客户端(例如桌面)应用程序上下文中的“MVC”的解释有些不同(因为 Web 应用程序必须位于请求-响应周期之上)。这只是使用 JavaFX 在胖客户端应用程序上下文中实现 MVC 的一种方法。

Your Person类并不是真正的模型,除非您有一个非常简单的应用程序:这通常是我们所说的域对象,模型将包含对其的引用以及其他数据。在狭隘的背景下,例如当你just思考ListView,你可以想到Person作为您的数据模型(它对每个元素中的数据进行建模ListView),但在更广泛的应用程序上下文中,需要考虑更多数据和状态。

如果您正在显示一个ListView<Person>您需要的数据至少是ObservableList<Person>。您可能还想要一个属性,例如currentPerson,这可能代表列表中选定的项目。

If the only您拥有的视图是ListView,然后创建一个单独的类来存储它就太过分了,但任何实际的应用程序通常都会有多个视图。此时,在模型中共享数据成为不同控制器相互通信的一种非常有用的方式。

因此,例如,您可能有这样的内容:

public class DataModel {

    private final ObservableList<Person> personList = FXCollections.observableArrayList();
    
    private final ObjectProperty<Person> currentPerson = new SimpleObjectPropery<>(null);

    public ObjectProperty<Person> currentPersonProperty() {
        return currentPerson ;
    }

    public final Person getCurrentPerson() {
        return currentPerson().get();
    }

    public final void setCurrentPerson(Person person) {
        currentPerson().set(person);
    }

    public ObservableList<Person> getPersonList() {
        return personList ;
    }
}

现在你可能有一个控制器ListView显示如下:

public class ListController {

    @FXML
    private ListView<Person> listView ;

    private DataModel model ;

    public void initModel(DataModel model) {
        // ensure model is only set once:
        if (this.model != null) {
            throw new IllegalStateException("Model can only be initialized once");
        }

        this.model = model ;
        listView.setItems(model.getPersonList());

        listView.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) -> 
            model.setCurrentPerson(newSelection));

        model.currentPersonProperty().addListener((obs, oldPerson, newPerson) -> {
            if (newPerson == null) {
                listView.getSelectionModel().clearSelection();
            } else {
                listView.getSelectionModel().select(newPerson);
            }
        });
    }
}

该控制器本质上只是将列表中显示的数据绑定到模型中的数据,并确保模型的currentPerson始终是列表视图中选定的项目。

现在您可能有另一个视图,例如编辑器,其中包含三个文本字段firstName, lastName, and email一个人的属性。它的控制器可能看起来像:

public class EditorController {

    @FXML
    private TextField firstNameField ;
    @FXML
    private TextField lastNameField ;
    @FXML
    private TextField emailField ;

    private DataModel model ;

    public void initModel(DataModel model) {
        if (this.model != null) {
            throw new IllegalStateException("Model can only be initialized once");
        }
        this.model = model ;
        model.currentPersonProperty().addListener((obs, oldPerson, newPerson) -> {
            if (oldPerson != null) {
                firstNameField.textProperty().unbindBidirectional(oldPerson.firstNameProperty());
                lastNameField.textProperty().unbindBidirectional(oldPerson.lastNameProperty());
                emailField.textProperty().unbindBidirectional(oldPerson.emailProperty());
            }
            if (newPerson == null) {
                firstNameField.setText("");
                lastNameField.setText("");
                emailField.setText("");
            } else {
                firstNameField.textProperty().bindBidirectional(newPerson.firstNameProperty());
                lastNameField.textProperty().bindBidirectional(newPerson.lastNameProperty());
                emailField.textProperty().bindBidirectional(newPerson.emailProperty());
            }
        });
    }
}

现在,如果您进行设置以使这两个控制器共享同一模型,则编辑器将编辑列表中当前选定的项目。

加载和保存数据应通过模型完成。有时,您甚至会将其分解到模型具有引用的单独类中(例如,允许您在基于文件的数据加载器和数据库数据加载器或访问 Web 服务的实现之间轻松切换)。在简单的情况下你可能会这样做

public class DataModel {

    // other code as before...

    public void loadData(File file) throws IOException {

        // load data from file and store in personList...

    }

    public void saveData(File file) throws IOException {
 
        // save contents of personList to file ...
    }
}

那么您可能有一个提供对此功能的访问的控制器:

public class MenuController {

    private DataModel model ;

    @FXML
    private MenuBar menuBar ;

    public void initModel(DataModel model) {
        if (this.model != null) {
            throw new IllegalStateException("Model can only be initialized once");
        }
        this.model = model ;
    }

    @FXML
    public void load() {
        FileChooser chooser = new FileChooser();
        File file = chooser.showOpenDialog(menuBar.getScene().getWindow());
        if (file != null) {
            try {
                model.loadData(file);
            } catch (IOException exc) {
                // handle exception...
            }
        }
    }

    @FXML
    public void save() {

        // similar to load...

    }
}

现在您可以轻松地组装应用程序:

public class ContactApp extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {

        BorderPane root = new BorderPane();
        FXMLLoader listLoader = new FXMLLoader(getClass().getResource("list.fxml"));
        root.setCenter(listLoader.load());
        ListController listController = listLoader.getController();

        FXMLLoader editorLoader = new FXMLLoader(getClass().getResource("editor.fxml"));
        root.setRight(editorLoader.load());
        EditorController editorController = editorLoader.getController();

        FXMLLoader menuLoader = new FXMLLoader(getClass().getResource("menu.fxml"));
        root.setTop(menuLoader.load());
        MenuController menuController = menuLoader.getController();

        DataModel model = new DataModel();
        listController.initModel(model);
        editorController.initModel(model);
        menuController.initModel(model);

        Scene scene = new Scene(root, 800, 600);
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

正如我所说,这种模式有很多变体(这可能更多的是模型-视图-呈现器,或“被动视图”变体),但这是一种方法(我基本上喜欢的一种方法)。通过控制器的构造函数向控制器提供模型会更自然一些,但是用fx:controller属性。这种模式也非常适合依赖注入框架。

Update:这个例子的完整代码是here https://github.com/james-d/SimpleMVP.

如果您对 JavaFX 中的 MVC 教程感兴趣,请参阅:

  • 伊甸园编码教程:如何在JavaFX中应用MVC https://edencoding.com/mvc-in-javafx/
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将 MVC 与 JavaFx 一起应用 的相关文章

  • 插入最大日期(独立于数据库)

    在我的本地设置中 我使用一个简单的 H2 数据库 托管 解决方案将有另一个 类似但不相同 数据库 我需要将最大可能日期插入到日期时间列中 我尝试使用 Instant MAX 但是 这会导致列中出现 169104626 12 11 20 08
  • 如何创建一个显示 Spinners 的 x 和 y 值的表格?

    我想创建一个位于图表右侧的表格 其中显示 2 列 x 和 y 值已输入到xSpin and ySpin旋转器 我已经画了一张我想要桌子放置的位置的图 我尝试过在网格窗格布局中使用文本框来创建表格并将值直接输入到文本框网格中 但是我无法将它们
  • java中如何连接字符串

    这是我的字符串连接代码 StringSecret java public class StringSecret public static void main String args String s new String abc s co
  • 运行具有外部依赖项的 Scala 脚本

    我在 Users joe scala lib 下有以下 jar commons codec 1 4 jar httpclient 4 1 1 jar httpcore 4 1 jar commons logging 1 1 1 jar ht
  • 如何安全地解决这个 Java 上下文类加载器问题?

    我的数百名用户中只有一位在启动我的 Java 桌面应用程序时遇到问题 他只有大约三分之一的时间开始 另外三分之二的时间在启动时抛出 NullPointerException Exception in thread AWT EventQueu
  • 在 S3 中迭代对象时出现“ConnectionPoolTimeoutException”

    我已经使用 aws java API 一段时间了 没有遇到太多问题 目前我使用的是库 1 5 2 版本 当我使用以下代码迭代文件夹内的对象时 AmazonS3 s3 new AmazonS3Client new PropertiesCred
  • 画透明圆,外面填充

    我有一个地图视图 我想在其上画一个圆圈以聚焦于给定区域 但我希望圆圈倒转 也就是说 圆的内部不是被填充 而是透明的 其他所有部分都被填充 请参阅这张图片了解我的意思 http i imgur com zxIMZ png 上半部分显示了我可以
  • hibernate锁等待超时超时;

    我正在使用 Hibernate 尝试模拟对数据库中同一行的 2 个并发更新 编辑 我将 em1 getTransaction commit 移至 em1 flush 之后我没有收到任何 StaleObjectException 两个事务已成
  • 在 Netbeans 8 上配置 JBoss EAP 的问题

    我已经下载了 JBoss EAP 7 并正在 Netbeans 8 上配置它 我已经到达向导 实例属性 其中要求从选择框中选择 域 当我打开选择框时 它是空的 没有什么可以选择的 因此 完成 按钮也处于非活动状态 这使得无法完成配置 我通过
  • Java 中的“Lambdifying”scala 函数

    使用Java和Apache Spark 已用Scala重写 面对旧的API方法 org apache spark rdd JdbcRDD构造函数 其参数为 AbstractFunction1 abstract class AbstractF
  • 很好地处理数据库约束错误

    再一次 它应该很简单 我的任务是在我们的应用程序的域对象中放置一个具有唯一约束的特定字段 这本身并不是一个很大的挑战 我刚刚做了以下事情 public class Location more fields Column unique tru
  • 普罗米修斯指标 - 未找到

    我有 Spring Boot 应用程序 并且正在使用 vertx 我想监控服务和 jvm 为此我选择了 Prometheus 这是我的监控配置类 Configuration public class MonitoringConfig Bea
  • Struts 2 + Sitemesh 3 集成 - FreemarkerDecoratorServlet 中的 NPE

    我将 Struts 2 版本 2 3 14 3 与 Sitemesh 3 版本 3 0 alpha 2 一起使用 并且在某些情况下遇到 NullPointerException 首先 这是我的 web xml 中的 struts2 site
  • 如何在JSTL中调​​用java方法? [复制]

    这个问题在这里已经有答案了 这可能是重复的问题 我只想调用不是 getter 或 setter 方法的方法例如 xyz 类的 makeCall someObj stringvalue Java类 Class XYZ public Strin
  • 将 Azure AD 高级自定义角色与 Spring Security 结合使用以进行基于角色的访问

    我创建了一个演示 Spring Boot 应用程序 我想在其中使用 AD 身份验证和授权 并使用 AD 和 Spring Security 查看 Azure 文档 我执行了以下操作 package com myapp contactdb c
  • 具有特定参数的 Spring AOP 切入点

    我需要创建一个我觉得很难描述的方面 所以让我指出一下想法 com x y 包 或任何子包 中的任何方法 一个方法参数是接口 javax portlet PortletRequest 的实现 该方法中可能有更多参数 它们可以是任何顺序 我需要
  • Trie 数据结构 - Java [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 是否有任何库或文档 链接提供了在 java 中实现 Trie 数据结构的更多信息 任何帮助都会很棒 Thanks 你可以阅读Java特里树
  • 带有 Maven Wrapper 的 Java 17 导致无法识别的 VM 选项“MaxPermSize=512m”

    I use OpenJDK 17 https jdk java net 17 使用 Maven Wrapper 3 8 2 从春季初始化 https start spring io Maven项目 JAR打包 Java 17 Spring
  • GUI Java 程序 - 绘图程序

    我一直试图找出我的代码有什么问题 这个想法是创建一个小的 Paint 程序并具有红色 绿色 蓝色和透明按钮 我拥有我能想到的让它工作的一切 但无法弄清楚代码有什么问题 该程序打开 然后立即关闭 import java awt import
  • 如何修复:“无法解析类型 java.lang.CharSequence。它是从所需的 .class 文件间接引用的”消息? [复制]

    这个问题在这里已经有答案了 我正在尝试使用这个字符串 amountStr amountStr replace replace replace 但我收到一条错误消息 我知道我收到的错误消息是因为我刚刚发布的字符串已过时 所以我想知道该字符串的

随机推荐

  • java.io.IOException:不支持标记/重置

    我知道这个问题已经被问过很多次了 但在某些情况下有所不同 所以我无法弄清楚 当我在 Eclipse 中运行游戏时 一切都很顺利 游戏运行完美 但在导出后 它崩溃了 我可以打开游戏并在菜单中移动 但没有播放任何声音 并且在我点击播放后 游戏就
  • 查找数组中第一个非零值索引

    我有一个数组数组 0 0 0 0 3 2 5 6 15 9 0 0 7 23 我可以用类似的东西 indexOf 0 如果我想找到第一个零值索引 但是如何找到第一个非零值的索引或符合某些条件的索引 它可能看起来像 indexOf funct
  • 从 contentViewController 中解除 UIPopoverController?

    如果您想关闭弹出窗口 例如 从弹出窗口的 contentViewController 中的按钮 您必须 创建对弹出窗口的引用 该引用由创建它的视图控制器保存 从 contentViewController 创建一个通知 让所属视图控制器知道
  • 在 VB.net 中将竖线分隔文件更改为逗号分隔

    所以我有一组管道分隔的输入 如下所示 787291 3224325523 37826427 37826427 2482472 2482472 46284729 46246 24682 82524 6846419 68247 我使用下面给出的
  • 干扰器 helloworld 示例

    我想学习颠覆者框架 http code google com p disruptor 谁能给我一个用Java语言在main方法中运行的helloworld例子 这是一个简单的 可运行的示例 说明如何使用 Disruptor 库 示例是使用
  • 卸载 oh-my-zsh 时遇到问题?

    我在 OSX 上 想要切换回原来的 zsh 配置哦我的zsh http github com robbyrussell oh my zsh 但是当我运行uninstall脚本它给了我一个错误 sudo uninstall oh my zsh
  • dxDataGrid - 如何刷新小部件

    当我单击按钮时 刷新不起作用 如果目的是添加到数据库按钮 请按按钮进入屏幕 但就是不更新 我用ajax创建了一个数据网格 我也在ViewModel中写了刷新功能 不刷新可能是什么原因 我的数据是json ajax type GET url
  • 如何使用python中的lambda函数在通过S3连接的AWS athena中进行查询

    我将 csv 文件保存在 S3 存储桶中 我可以使用AWS Athena查询S3的数据 有什么方法可以将 lambda 函数连接到 athena 并从 lambda 函数查询数据 请帮忙 Thanks 正如 Chris Pollard 所说
  • 如何捕捉Tk中的最大化信号?

    您可以通过以下方式将命令与窗口的 X 按钮绑定 wm protocol windowPath WM DELETE WINDOW command 如何对窗口的最大化按钮执行相同的操作 X11 中也没有标准协议ICCCM套 http tronc
  • HTML 选择选项文本等宽

    我正在尝试选择使用等宽字体的选项 以便当您单击下拉菜单时它们会垂直排列 我试图将代码左对齐 后跟破折号 然后是描述 我使用编码空格添加了选项 以便每个选项在破折号之前具有相同数量的字符 但它们仍然没有对齐 我尝试了新的快递和等宽字体 我可以
  • php中相应的嵌套三元运算符? [复制]

    这个问题在这里已经有答案了 我想转换以下if else condition to nested ternary操作员 if projectURL echo projectURL elseif project project url echo
  • 如何知道php邮件发送失败

    我正在从 php mail 发送邮件 如果发送到目的地失败 我希望收到失败消息 to email protected cdn cgi l email protection email from email protected cdn cgi
  • net::ERR_ABORTED 429 仅通过本地主机使用 ipinfo.io

    我想从前端设备获取 IP 地址 我发现this https ipinfo io developers名为 IPINFO io 的免费 API 根据使用 Jquery 获取 IP 地址的文档 我需要做的就是 get https ipinfo
  • 如何在网络驱动程序中检查页面是否已完全加载?

    我正在编写一些 Java Webdriver 代码来自动化我的应用程序 如何正确判断页面是否已加载 该应用程序也有一些 Ajax 调用 我已经声明了对 WebDriver 的隐式等待 硒会为你做到这一点 或者至少它尽力了 有时它会达不到要求
  • 使用 sse 内在函数时如何打破循环?

    m128 pSrc1 m128 string m128 m0 mm set ps1 0 null character while 1 m128 result m128 mm cmpeq ss pSrc1 m0 if character is
  • 子菜单未完全并排定位

    我发现了一个问题 sub menu code left and transform translateX 所以我将位置更改为相对位置并使用上面的两个代码重新定位 它似乎有效 但现在我拥有的两个子菜单不再并排 他们所做的只是相距几厘米顶部 不
  • 为什么我的 NSMutableDictionary 为零?

    我正在尝试将数组存储在 NSMutableDictionary 中 但是 在我为其设置对象后 NSMutableDictionary 为空 这是我的代码 感谢任何帮助 NSMutableArray arrTemp NSMutableArra
  • 验证电子邮件地址

    我正在尝试使用以下代码使用 C 发送电子邮件 MailMessage mail new MailMessage mail From new MailAddress fromAddress friendlyName mail To Add t
  • 抽象类的shared_ptr向量到副本向量

    我有一个带有共享指针的向量 std vector
  • 将 MVC 与 JavaFx 一起应用

    我是 GUI 世界 OO 设计模式的新手 我想在我的 GUI 应用程序中使用 MVC 模式 我已经阅读了一些关于 MVC 模式的教程 模型将包含数据 视图将包含视觉元素和控制器将连接视图和模型 我有一个包含 ListView 节点的视图 并