简体   繁体   English

Java观察者/可观察的更新

[英]Java Observer/Observable update

I've tried to apply the Observable/Observer pattern but there is something wrong with my code when I try to change a the textfield of a JTextPane . 我尝试应用Observable / Observer模式,但是当我尝试更改JTextPane的textfield时,我的代码出了点问题。

I've got 3 classes, Play , Controller and SecondWindow here are a sample of their code. 我有3个类, PlayControllerSecondWindow这是它们的代码示例。

public class Play() {
    Controller c = new Controller();
    SecondWindow sw = new SecondWindow();
    c.addObserver(sw)

    c.setText("blabla");
}

My class Controller : 我的类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();
    }
}

and SecondWindow : 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
    }

I can't manage to put the variable c in the textField (like a txt.setText(c.getText) instruction). 我无法将变量c放在textField中(例如txt.setText(c.getText)指令)。 I'm sure that it reads the method update, but I don't know how to make sure it works. 我确定它读取方法更新,但是我不知道如何确保它有效。

Hint: Per the Observerable API the notifyObservers method has an overload that accepts any object as a parameter: 提示:根据Observerable API ,notifyObservers方法具有一个重载,该重载接受任何对象作为参数:

public void notifyObservers(Object arg)

This can even be a String. 甚至可以是一个字符串。 And as per the Observer API , this object is then passed into the update method in the observer, and you can use it there. 然后按照Observer API的要求 ,将此对象传递到观察器中的update方法中,您可以在其中使用它。

 void update(Observable o, Object arg) 

arg - an argument passed to the notifyObservers method. arg-传递给notifyObservers方法的参数。


Separate side issue here: 单独问题在这里:

contentPane.setLayout(null); contentPane.setLayout(NULL);

For most Swing aficionados, seeing this is like hearing nails on a chalkboard -- it's painful. 对于大多数Swing爱好者来说,看到这就像在黑板上钉钉子一样-十分痛苦。 While null layouts and setBounds() might seem to Swing newbies like the easiest and best way to create complex GUI's, the more Swing GUI'S you create the more serious difficulties you will run into when using them. 尽管null布局和setBounds()似乎是Swing新手喜欢创建复杂GUI的最简单和最佳方法,但您创建的Swing GUI越多,使用它们时将遇到的困难就越大。 They won't resize your components when the GUI resizes, they are a royal witch to enhance or maintain, they fail completely when placed in scrollpanes, they look gawd-awful when viewed on all platforms or screen resolutions that are different from the original one. 当GUI调整大小时,它们不会重新调整组件的大小;它们是需要增强或维护的皇家女巫;放置在滚动窗格中时,它们会完全失败;在所有平台或与原始分辨率不同的屏幕分辨率下查看时,它们看起来都是令人毛骨悚然的。 Instead you will want to study and learn the layout managers and then nest JPanels, each using its own layout manager to create pleasing and complex GUI's that look good on all OS's. 相反,您将需要学习和学习布局管理器,然后嵌套JPanels,每个JPanels都使用其自己的布局管理器来创建令人愉悦且复杂的GUI,在所有OS上都看起来不错。


Side issue number two: your code is not Swing thread safe, since the Swing GUI could very well be notified by the observable off of the Swing event dispatch thread or EDT. 侧问题二:你的代码是不是Swing线程安全的,因为Swing GUI的很可能是由观测到 Swing事件分派线程或EDT的通知。 While it is not likely to cause frequent or serious problems with this simple program, in general it would be better to use a SwingPropertyChangeSupport and PropertyChangeListeners rather than Observer / Observable if you can. 尽管使用此简单程序不太可能导致频繁或严重的问题,但是通常最好使用SwingPropertyChangeSupport和PropertyChangeListeners,而不是Observer / Observable。


Next Side Issue 下一
This: 这个:

public class Controller extends Observable(){

isn't compilable / kosher Java. 是不可编译的/犹太Java。 Same for the duplicate parameter-less constructors for the SecondWindow class. 对于SecondWindow类的重复的无参数构造函数,该方法相同。 Yes, we know what you're trying to do, but it's hard enough trying to understand someone else's code, you really don't want to make it harder by posting kind-of sort-of uncompilable code, trust me. 是的,我们知道您要执行的操作,但是要理解其他人的代码已经很困难了,您真的不想通过发布某种无法编译的代码来使其变得更困难,请相信我。


For example, something simple could be implemented in Swing using PropertyChangeListeners, like so: 例如,可以使用PropertyChangeListeners在Swing中实现一些简单的操作,如下所示:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM