MVC - Swing 与 JavaFX 的实现

Posted

技术标签:

【中文标题】MVC - Swing 与 JavaFX 的实现【英文标题】:MVC - Implementation with Swing vs JavaFX 【发布时间】:2020-07-24 22:21:01 【问题描述】:

我有一个 2D 游戏引擎的宠物项目。 创建所有后端功能后,我想为它实现一个 UI。 我目前的计划是通过 MVC 做到这一点,因为它让我觉得这是最可行的方法(首先是逻辑,然后是 UI)。 现在,我不确定如何使用 Swing 或 JavaFX 设计/实现它,因为我还没有完全理解它们的基本概念是什么。 有人可以向我描述如何使用 Swing 或 JavaFX 实现 MVC 吗?

【问题讨论】:

The MVC pattern and Swing. 【参考方案1】:

您可以拥有一个通用模型,可供不同视图使用。 为了演示它,我们首先介绍一个可以用来监听此类模型的接口:

//Interface implemented by SwingView and used by Model
interface Observer 
    void observableChanged();

考虑一个非常简单的模型,只有一个属性:0 到某个最大值之间的整数值:

//Generic model. Not dependent on the GUI tool kit. Use by Swing as well as JAvaFX
class Model 

    private int value;
    private static final int MAX_VALUE = 100;
    private Observer observer;

    int getValue()
        return value;
    

    void setValue(int value)
        this.value = Math.min(MAX_VALUE, Math.abs(value));
        notifyObserver();
    

    int getMaxValue() 
        return MAX_VALUE;
    

    //-- handle observers

    void setObserver(Observer observer) 
        this.observer = observer;
    

    private void notifyObserver() 
        if(observer != null) 
            observer.observableChanged();
        
    

请注意,当value 更改模型时,模型会调用observer.observableChanged()。 现在让我们将此模型与显示随机数的Swing gui 一起使用:

import java.awt.*;
import java.util.Random;
import javax.swing.*;

//Swing app, using a generic model
public class SwingMVC 

    public static void main(String[] args) 
        new SwingController();
    


//SwingController of the MVC pattern."wires" model and view (and in this case also worker)
class SwingController

    public SwingController() 
        Model model = new Model();
        SwingView swingView = new SwingView(model);
        model.setObserver(swingView); //register view as an observer to model
        update(model);
    

    //change model
    private void update(Model model) 
        Random rnd = new Random();
        //use swing timer so the change is performed on the Event Dispatch Thread
        new Timer(1000,(e)-> model.setValue(1+rnd.nextInt(model.getMaxValue()))).start();
    


//view of the MVC pattern. Implements observer to respond to model changes
class SwingView implements Observer

    private final Model model;
    private final JLabel label;

    public SwingView(Model model) 

        this.model = model;
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationByPlatform(true);
        frame.setLayout(new GridBagLayout());
        label = new JLabel(" - ");
        label.setFont(new Font(label.getFont().getName(), Font.PLAIN, 48));
        label.setHorizontalTextPosition(SwingConstants.CENTER);
        frame.add(label);
        frame.pack();
        frame.setVisible(true);
    

    @Override
    public void observableChanged() 
        //update text in response to change in model
        label.setText(String.format("%d",model.getValue()));
    

我们可以使用相同的模型并通过JavaFx gui 实现相同的功能:

import java.util.Random;
import javafx.animation.PauseTransition;
import javafx.application.Application;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.Duration;

//JavaFa app, using a generic model
public class FxMVC extends Application

    @Override
    public void start(Stage primaryStage) throws Exception 

        FxController fxController = new FxController();
        Scene scene = new Scene(fxController.getParent());
        primaryStage.setScene(scene);
        primaryStage.show();
    

    public static void main(String[] args) 
        launch(null);
    


class FxController

    private final FxView view;

    FxController() 
        Model model = new Model();
        view = new FxView(model);
        model.setObserver(view); //register fxView as an observer to model
        update(model);
    

    //change model
    private void update(Model model) 
        Random rnd = new Random();
        //use javafx animation tools so the change is performed on the JvaxFx application thread
        PauseTransition pt = new PauseTransition(Duration.seconds(1));
        pt.play();
        pt.setOnFinished(e->
            model.setValue(1+rnd.nextInt(model.getMaxValue()));
            pt.play();
        );
    

    Parent getParent()
        return view;
    


//View of the MVC pattern. Implements observer to respond to model changes
class FxView extends StackPane implements Observer

    private final Model model;
    private final Label label;

    public FxView(Model model) 
        this.model = model;
        label = new Label(" - ");
        label.setFont(new Font(label.getFont().getName(), 48));
        getChildren().add(label);
    

    @Override
    public void observableChanged()  //update text in response to change in model
        //update text in response to change in model
        label.setText(String.format("%d",model.getValue()));
    

另一方面,您可以拥有一个更具体的模型,旨在与特定工具包一起使用,并通过使用该工具包的某些工具获得一些优势。 例如使用JavaFx 属性制作的模型,在此示例中为SimpleIntegerProperty,它简化了对模型更改的侦听(不使用Observer 接口):

import java.util.Random;
import javafx.animation.PauseTransition;
import javafx.application.Application;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.value.ChangeListener;
import javafx.scene.*;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.Duration;

//JavaFa app, using a JavaFx model
public class FxApp extends Application

    @Override
    public void start(Stage primaryStage) throws Exception 

        FxController fxController = new FxController();
        Scene scene = new Scene(fxController.getParent());
        primaryStage.setScene(scene);
        primaryStage.show();
    

    public static void main(String[] args) 
        launch(null);
    


class FxAppController

    private final FxAppView view;

    FxAppController() 
        FxAppModel model = new FxAppModel();
        view = new FxAppView(model);
        update(model);
    

    //change model
    private void update(FxAppModel model) 
        Random rnd = new Random();
        //use javafx animation tools so the change is performed on the JvaxFx application thread
        PauseTransition pt = new PauseTransition(Duration.seconds(1));
        pt.play();
        pt.setOnFinished(e->
            model.setValue(1+rnd.nextInt(model.getMaxValue()));
            pt.play();
        );
    

    Parent getParent()
        return view;
    


//View does not need to implement listener
class FxAppView extends StackPane

    public FxAppView(FxAppModel model) 
        Label label = new Label(" - ");
        label.setFont(new Font(label.getFont().getName(), 48));
        getChildren().add(label);
        model.getValue().addListener((ChangeListener<Number>) (obs, oldV, newV) -> label.setText(String.format("%d",model.getValue())));
    


//Model that uses JavaFx tools
class FxAppModel 

    private SimpleIntegerProperty valueProperty;
    private static final int MAX_VALUE = 100;

    SimpleIntegerProperty getValue()
        return valueProperty;
    

    void setValue(int value)
        valueProperty.set(value);
    

    int getMaxValue() 
        return MAX_VALUE;
    


一个Swing gui 和一个JavaFx gui,每个都使用相同Model 的不同实例:

【讨论】:

那么,关于动画,你会推荐哪一个?选择 Swing 还是 JavaFX? 您可能会发现this 很有帮助。

以上是关于MVC - Swing 与 JavaFX 的实现的主要内容,如果未能解决你的问题,请参考以下文章

带有 SWING 与 JavaFX 的 Java 用户界面

从 Swing 转换为 JavaFX?

在 JFXPanel 中嵌入 JavaFX 阶段(Swing 嵌入)

是否可以使用 JavaFX 和 Swing 制作具有视觉吸引力的 GUI?

在 Swing 应用程序中使用 JavaFX 图表

JAVAFX-1 开发应用