Обновление GUI в ответ на изменения модели - PullRequest
2 голосов
/ 27 марта 2020

Я делаю свой первый Java проект, который включает GUI. Я знаю, что логи c программы должны быть отделены от вида (GUI) программы. Моя проблема в том, что я не понимаю, как обновить GUI после того, как что-то изменится в логи c игры, без кодирования дважды, один раз в GUI и один раз в логи c.

Вот очень упрощенный пример того, что я пытаюсь сделать:

Класс для логики c:

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 и logi c, потому что программа alomost уже знает все, что должна знать: как работает logi c и как отображается logi c. Это означает, что мое чувство говорит, что реализовать ActionListener, так как

button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                logic.increaseImportantVariable();
                showVariableLabel.setText(String.valueOf(logic.getImportantVariable()));
            }
        });

- не самый лучший из возможных подходов, даже если он работает (я здесь не прав?). Я думаю, потому что реальный проект был бы намного более сложным, и многие переменные могли бы измениться в логи c, что упростило бы обновление всего GUI, а не только компонентов, которые изменились.

Так что я ищу, чтобы либо только изменить логи c и постоянно обновлять весь GUI (который знает, как показать весь логи c), либо вызвать что-то вроде gui .update (), когда что-то меняется в лог c для обновления всего GUI. Но в обоих случаях я понятия не имею, как это сделать. Я надеюсь, что моя проблема понятна, и у меня нет большой ошибки, когда я думаю о том, как наилучшим образом разделить логи c и GUI.

1 Ответ

1 голос
/ 28 марта 2020

Чтобы прослушать изменения модели, введите интерфейс слушателя:

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