MVC - Реализация с Swing против JavaFX - PullRequest
0 голосов
/ 12 апреля 2020

У меня есть проект для домашних животных, который представляет собой движок 2D-игр.
После создания всей функциональности бэкэнда я хочу реализовать для него пользовательский интерфейс.
Мой текущий план состоит в том, чтобы сделать это через MVC, потому что это Мне кажется, что это самый приемлемый способ сделать это (сначала logi c, а затем UI). Теперь я не уверен, как спроектировать / реализовать это с помощью Swing или JavaFX, так как я еще не до конца понимаю, каковы основные концепции обоих. Может кто-нибудь описать мне, как реализовать MVC с Swing или JavaFX?

1 Ответ

2 голосов
/ 12 апреля 2020

У вас может быть общая модель, которая может использоваться различными видами. Чтобы продемонстрировать это, давайте сначала представим интерфейс, который можно использовать для прослушивания такой модели:

//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();
        }
    }
}

Обратите внимание, что модель вызывает observer.observableChanged(), когда value меняет ее. Теперь давайте используем эту модель с 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()));
    }
}

С другой стороны, вы можете иметь модель, которая является более точной c, предназначенной для использования с указанным c набором инструментов, и получить некоторые преимущества, используя некоторый инструмент этого Инструментарий. Например, модель, созданная с использованием свойств 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;
    }
}

A Swing gui и JavaFx gui, каждый использует разные экземпляры одного и того же Model:

enter image description here

...