Java观察者/可观察的更新



我尝试应用观察者/观察者模式,但是当我尝试更改 JTextPane的文本字段时,我的代码有问题。

我有3个类,PlayControllerSecondWindow,这是其代码的示例。

public class Play() {
    Controller c = new Controller();
    SecondWindow sw = new SecondWindow();
    c.addObserver(sw)
    c.setText("blabla");
}

我的类Controller

public class Controller extends Observable(){
    private String text ="";
    private static Controller getInstance() {
        if (instance == null) {
            instance = new Controller();
        }
        return instance;
    }
    public void setText(String s) {
        text = s;
        setChanged();
        notifyObservers();
    }
}

SecondWindow

public class SecondWindow extends JFrame implements Observer{
    private JPanel contentPane;
    private Controller c;
    private JTextPane txt = new JTextPane();
    public SecondWindow () {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    SecondWindow frame = new SecondWindow();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
    public SecondWindow() {
        initComponents();
        createEvents();
        c = Controller.getInstance();
    }
    public void initComponents() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(1000, 0, 300,500);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        contentPane.setLayout(null);
        txt.setBounds(0, 0, 280, 460);
        txt.enable(false);
        contentPane.add(txt);
    }
    public void update(Observable arg0 , Object arg1){
        // Things to change here
    }

我无法设法将变量c放在TextField(例如txt.setText(c.getText)指令)中。我敢肯定它会读取方法更新,但是我不知道如何确保它有效。

提示:根据可观察的API,NotifyObservers方法的过载可以接受任何对象作为参数:

public void notifyObservers(Object arg)

这甚至可以是字符串。根据观察者API,然后将此对象传递到观察者中的更新方法中,您可以在那里使用它。

void update(Observable o,
        Object arg)

arg-一个参数传递给notifyobservers方法。


在这里分开的侧面问题:

contentpane.setlayout(null);

对于大多数摇摆的狂热者来说,看到这就像在黑板上听到指甲 - 这很痛苦。虽然Null布局和setBounds()似乎像创建复杂的GUI的最简单和最佳方法一样摆动新手,但使用它们时,使用它们时就会遇到越严重的困难。它们不会调整您的组件大小时,当GUI大小时,它们是一个可以增强或维护的皇家女巫,当放置在卷轴上时,它们完全失败,当在所有平台或屏幕分辨率上观看时,它们看起来很可怕。相反


侧面问题第二:您的代码不是摇摆线程安全的,因为摇摆GUI很可能会被摇摆事件dispatch thread或EDT的可观察到的 Off 通知。虽然这个简单程序不太可能引起频繁或严重的问题,但总的来说,最好使用swingpropertychangesupport和propertyChangeListeners,而不是观察者/可观察者。


下一个侧面问题
这个:

public class Controller extends Observable(){

不可编译/犹太爪哇。对于第二个窗口类的无重复参数构造函数也相同。是的,我们知道您要做什么,但是很难理解别人的代码,您真的不想通过发布某种不可兼容的代码来使它变得更加困难,请相信我。


例如,可以使用PropertyChangeListeners在挥杆中实现一些简单的东西,例如:

import java.util.concurrent.TimeUnit;
public class Play2 {
    public static void main(String[] args) {
        Model2 model2 = new Model2();
        View2 view2 = new View2();
        new Controller2(model2, view2);
        view2.show();
        for (int i = 0; i < 10; i++) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                // one of the few times it's OK to ignore an exception
            }
            String text = String.format("Counter Value: %d", i);
            model2.setText(text);
        }
    }
}

import java.beans.PropertyChangeListener;
import javax.swing.event.SwingPropertyChangeSupport;
public class Model2 {
    private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(this);
    public static final String TEXT = "text"; // name of our "bound" property
    private String text = "";
    public String getText() {
        return text;
    }
    public void setText(String text) {
        String oldValue = this.text;
        String newValue = text;
        this.text = text;
        pcSupport.firePropertyChange(TEXT, oldValue, newValue);
    }
    public void addPropertyChangeListener(PropertyChangeListener listener) {
        pcSupport.addPropertyChangeListener(listener);
    }
    public void removePropertyChangeListener(PropertyChangeListener listener) {
        pcSupport.removePropertyChangeListener(listener);
    }
    public void addPropertyChangeListener(String name, PropertyChangeListener listener) {
        pcSupport.addPropertyChangeListener(name, listener);
    }
    public void removePropertyChangeListener(String name, PropertyChangeListener listener) {
        pcSupport.removePropertyChangeListener(name, listener);
    }
}

import javax.swing.*;
public class View2 {
    private JPanel mainPanel = new JPanel();
    private JTextField textField = new JTextField(10);
    public View2() {
        textField.setFocusable(false);
        mainPanel.add(new JLabel("Text:"));
        mainPanel.add(textField);
    }
    public JPanel getMainPanel() {
        return mainPanel;
    }
    public void setText(String text) {
        textField.setText(text);
    }
    public void show() {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("View");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(getMainPanel());
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
public class Controller2 {
    private Model2 model2;
    private View2 view2;
    public Controller2(Model2 model2, View2 view2) {
        this.model2 = model2;
        this.view2 = view2;
        model2.addPropertyChangeListener(Model2.TEXT, new ModelListener());
    }
    private class ModelListener implements PropertyChangeListener {
        @Override
        public void propertyChange(PropertyChangeEvent pcEvt) {
            view2.setText((String) pcEvt.getNewValue());
        }
    }
}

最新更新