java - 更新 GUI 以响应模型更改
问题描述
我正在做我的第一个包含 GUI 的 Java 项目。我知道程序的逻辑应该与程序的视图(GUI)分开。我的问题是,我不明白如何在游戏逻辑发生变化后更新 GUI,而无需对其进行两次编码,一次在 GUI 中,一次在逻辑中。
这是我尝试做的一个非常简化的示例:
逻辑类:
public class Logic {
private int importantVariable;
public Logic(int importantVariable){
this.importantVariable = importantVariable;
}
public int getImportantVariable() {
return importantVariable;
}
public void increaseImportantVariable() {
this.importantVariable++;
}
}
GUI 类
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class GUI extends JFrame {
private Logic logic;
public GUI(Logic logic){
this.logic = logic;
this.setTitle("GUI");
this.setSize(1200, 800);
this.setLocationRelativeTo(null);//set the location to the middle of the display
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel guiPanel = new JPanel();
//create label
JLabel showVariableLabel = new JLabel(String.valueOf(logic.getImportantVariable()));
guiPanel.add(showVariableLabel);
//create Button
JButton button = new JButton();
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
logic.increaseImportantVariable();
}
});
guiPanel.add(button);
this.add(guiPanel);
}
}
主类:
public class Main{
public static void main(String[] args){
Logic logic = new Logic(0);
GUI gui = new GUI(logic);
gui.setVisible(true);
}
}
在本例中,GUI 有一个按钮和一个显示数字的标签。如果按下按钮,数字会增加。但是如何使标签显示增加的数字?我认为更改 ActionListener 以更新 JLabel 和逻辑并不好,因为程序几乎已经知道它必须知道的一切:逻辑如何工作以及逻辑如何显示。这意味着我的感觉是将 ActionListener 实现为
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
logic.increaseImportantVariable();
showVariableLabel.setText(String.valueOf(logic.getImportantVariable()));
}
});
不是最好的方法,即使它有效(我错了吗?)。我认为这是因为一个真正的项目会更加复杂,并且许多变量可能会在逻辑中发生变化,从而更容易更新整个 GUI 而不仅仅是更改的组件。
所以我要寻找的是要么只更改逻辑并不断更新整个 GUI(它知道如何显示整个逻辑),要么在逻辑发生更改时调用类似 gui.update() 的东西来更新整个 GUI。但是对于这两种方式,我都不知道该怎么做。我希望我的问题是可以理解的,并且我在思考如何以最佳方式分离逻辑和 GUI 方面没有大错误。
解决方案
要监听模型更改,请引入监听器接口:
interface ModelObserver {
void modelChanged();
}
修改Logic
使其可以接受侦听器并使用它:
class Logic {
ModelObserver observer;
private int importantVariable;
public Logic(int importantVariable, ModelObserver observer){
this.importantVariable = importantVariable;
this.observer = observer;
}
public int getImportantVariable() {
return importantVariable;
}
public void increaseImportantVariable() {
importantVariable++;
observer.modelChanged();
}
}
Main
类充当控制器,因此让它将观察者添加到Model
并响应模型更改:
public class Main implements ModelObserver{
private final GUI gui;
Main(){
Logic logic = new Logic(0, this);
gui = new GUI(logic);
gui.setVisible(true);
}
@Override
public void modelChanged() {
gui.refresh();
}
public static void main(String[] args){
new Main();
}
}
把它们放在一起(为了说服整个代码可以复制粘贴到Main.java
并运行):
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public class Main implements ModelObserver{
private final GUI gui;
Main(){
Logic logic = new Logic(0, this);
gui = new GUI(logic);
gui.setVisible(true);
}
@Override
public void modelChanged() {
gui.refresh();
}
public static void main(String[] args){
new Main();
}
}
interface ModelObserver {
void modelChanged();
}
class GUI extends JFrame {
private final Logic logic;
private final JLabel showVariableLabel;
public GUI(Logic logic){
this.logic = logic;
this.setTitle("GUI");
this.setLocationRelativeTo(null);//set the location to the middle of the display
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel guiPanel = new JPanel();
//create label
showVariableLabel = new JLabel(String.valueOf(logic.getImportantVariable()));
guiPanel.add(showVariableLabel);
//create Button
JButton button = new JButton("Increment");
button.addActionListener(e -> logic.increaseImportantVariable());
guiPanel.add(button);
this.add(guiPanel);
pack();
}
public void refresh() {
showVariableLabel.setText(String.valueOf(logic.getImportantVariable()));
}
}
class Logic {
ModelObserver observer;
private int importantVariable;
public Logic(int importantVariable, ModelObserver observer){
this.importantVariable = importantVariable;
this.observer = observer;
}
public int getImportantVariable() {
return importantVariable;
}
public void increaseImportantVariable() {
importantVariable++;
observer.modelChanged();
}
}
推荐阅读
- docker - 带有 Docker Compose 文件的 AWS ECS -“外部”Docker 卷
- google-cloud-platform - 在 CLI 中创建 GCP 项目,但无法将父级设为试用用户
- apache-spark - 火花运行 ./bin/spark-submit --master 本地示例/src/main/python/sql/arrow.py
- java - 在@PostConstruct中初始化bean时如何模拟bean的值
- git - merge=ours 的 git 属性不起作用
- android - 如何修复“原因:无效类型代码:85”错误
- python-3.x - 如何检查一个集合中的键值对是否匹配并使用python更新另一个mongodb集合中存在的键中的值
- amazon-web-services - 如何使用 Teamcity 在 AWS 实例上运行测试?
- python - Python 在一行中解压一个打包结构
- api - CDiscount:通过 Postman 发送 JSON Get 请求时出现问题