简体   繁体   English

将Swing GUI组件的属性绑定到自定义类方法(属性)

[英]Bind a Swing GUI component's property to a custom class method (property)

I'm working on my chat project. 我正在做我的聊天项目。 I've programmed server and client sides that works without GUI, just console UI. 我编写了无需GUI的服务器和客户端,只需控制台UI。 Now, while working on clients GUI (with Netbeans provided tools, not as I am used to code by myself), I've stuck on binding problem. 现在,在使用客户端GUI(使用Netbeans提供的工具,而不是我习惯自己编写代码)时,我一直坚持绑定问题。

Inside of ClientGui class I have Client object. ClientGui类中,我有Client对象。 In my GUI I want to disable input textfield until client isn't connected to a chat server. 在我的GUI中,我想禁用输入文本字段,直到客户端未连接到聊天服务器。 I've tried to bind (via Netbeans GUI) my input textfield's property enabled to that client object's method isConnected() (that returns boolean ). 我试图绑定(通过Netbeans GUI)我的输入文本字段的属性启用到该客户端对象的方法isConnected() (返回boolean )。 isConnected isn't just returning some variable's value, it's combined boolean expression. isConnected不只是返回一些变量的值,它是组合的布尔表达式。 So when user clicks to connect, it succeeds, but input textfield doesn't change it's state to enabled. 因此,当用户单击以进行连接时,它会成功,但输入文本字段不会将其状态更改为已启用。

So as I get it, I have to work with event and listeners and notify in my Client class? 所以当我得到它时,我必须使用事件和监听器并在我的Client类中通知? But what is point of binding then, as I could just have event fired on my Client and my input field listen to clients connected event? 但是接下来是什么点,因为我可以在我的Client上触发事件并且我的输入字段会监听客户端连接事件?

So I provide chunks of my code. 所以我提供了我的代码块。

The Client class: (You may see some lines with action listeners and event, I didn't remove them, just experimented) Client类:(您可能会看到一些带有动作侦听器和事件的行,我没有删除它们,只是进行了实验)

public class Client {
    private ClientListener listener;
    private ClientSender sender;
    private Socket connection;

    private boolean finnish = false;
    private PropertyChangeEvent connected;

    public Client(String hostname, int port) throws UnknownHostException, IOException {
        connection = new Socket(hostname, port);
    }

    public void start() {
        try {
            connected = new PropertyChangeEvent(this, "connected", null, connection);

            sender = new ClientSender(new ObjectOutputStream(connection.getOutputStream()));
            Thread senderThread = new Thread(sender);
            senderThread.start();
            Logger.getLogger(Client.class.getName()).log(Level.INFO, "Sender thread has started");

            listener = new ClientListener(new ObjectInputStream(connection.getInputStream()));
            Thread listenerThread = new Thread(listener);
            listenerThread.start();
            Logger.getLogger(Client.class.getName()).log(Level.INFO, "Listener thread has started");


        } catch (IOException ex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, "IO problems", ex);
        }
    }

    public ClientSender getSender() {
        return sender;
    }

    public void stop() {
        sender.stop();
        listener.stop();
    }

    public boolean isConnected() {
        return connection != null && !connection.isClosed();
    }
}

The Client GUI class: Client GUI类:

public class ClientGui extends javax.swing.JFrame {
    private Client client;

    public boolean getConnected() {
        System.out.println( client != null && client.isConnected());
        return client != null && client.isConnected();
    }

    /**
    * Creates new form ClientGui
    */
    public ClientGui() {
        initComponents();
    }

    // GENERATED CODE

private void tfUserInputKeyPressed(java.awt.event.KeyEvent evt) {
    if (evt.getKeyCode() == KeyEvent.VK_ENTER) {
        Message message = new Message("user", tfUserInput.getText());
        client.getSender().add(message);

        tfUserInput.setText("");
    }
}

private void btnConnectActionPerformed(java.awt.event.ActionEvent evt) {
    try {
        client = new Client(tfHostname.getText(), Integer.parseInt(tfPort.getText()));
        client.start();

    } catch (UnknownHostException ex) {
        Logger.getLogger(ClientGui.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IOException ex) {
        Logger.getLogger(ClientGui.class.getName()).log(Level.SEVERE, null, ex);
    }

}

// and somewhere GUI generated code of my binding (also tried with custom code, but no success)
 org.jdesktop.beansbinding.Binding binding =
 org.jdesktop.beansbinding.Bindings.createAutoBinding 
(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ, this,  
 org.jdesktop.beansbinding.ELProperty.create("${connected}"), listConversation,  
 org.jdesktop.beansbinding.BeanProperty.create("enabled"), "listConversationBinding");

 bindingGroup.addBinding(binding);

In fact it's a JList , but doesn't matter, because I want such binding for few components. 实际上它是一个JList ,但并不重要,因为我想要几个组件的这种绑定。 Here I try to use fake method in GUI Form, which calls clients connected (did it because don't how to add Client as a component). 在这里,我尝试在GUI窗体中使用伪方法,它调用客户端连接(这样做是因为不知道如何将Client添加为组件)。

I've read on forums, everywhere saying about beans and so on. 我在论坛上看过,到处都在谈论豆子等等。 I want my Client class to have least as possible code needed for GUI, interface implementations and calls for firing event and so on. 我希望我的Client类具有GUI,接口实现和触发事件调用等所需的最少代码。

UPDATE UPDATE

Very good! 很好! Thank you. 谢谢。 Why can't I bind so I don't have to use setEnabled(value) method (make that enabled property keeps track of boolean expression "property" ( connection != null && !connection.isClosed() ). Also, because of this trick I have to do setConnected(value) , even if this is resolved in runtime depending on a connection, and I even can't know old value (of course I can do private void setConnected(booleanvalue) and put calls to this with true or false depending on what happens in those places. Seems like my idea of using property is wrong, better do with actions or events. 为什么我不能绑定所以我不必使用setEnabled(value)方法(使该enabled属性跟踪布尔表达式“property”( connection != null && !connection.isClosed() )。另外,因为这个技巧我必须做setConnected(value) ,即使这是在运行时根据连接解决的,我甚至无法知道旧值(当然我可以做私有空setConnected(booleanvalue)并将调用放到这个是真还是假,取决于那些地方发生的事情。似乎我的使用财产的想法是错误的,更好地处理行动或事件。

You should add PropertyChangeSupport to the Client . 您应该将PropertyChangeSupport添加到Client

    final PropertyChangeSupport pcs = new PropertyChangeSupport(this);

    public void addPropertyChangeListener(PropertyChangeListener listener) {
             this.pcs.addPropertyChangeListener(listener);
    }


      boolean connected;

 public boolean isConnected() {
     return connected;
 }

 public void setConnected(boolean connected) {
     boolean oldValue = this.connected;
     this.value = connected;
     this.pcs.firePropertyChange("connected", oldValue, newValue);
 }

 .....


     public Client(String hostname, int port) throws UnknownHostException, IOException    {
    connection = new Socket(hostname, port);
    setConnected(connection != null && !connection.isClosed());
}

in the GUI 在GUI中

    public class ClientGui extends javax.swing.JFrame implements PropertyChangeListener
    .....
    propertyChanged(..){
      tfUserInput.setEnabled(true);
    }

     private void btnConnectActionPerformed(java.awt.event.ActionEvent evt) {
        try {
            client = new Client(tfHostname.getText(), Integer.parseInt(tfPort.getText()));
            client.addPropertyChangeListener(this);
            client.start();
        .....

Melasse框架缓解了模型/视图(ui组件)之间的这种绑定的痛苦,在大多数情况下甚至不需要编写额外的匿名类: https//github.com/cchantep/melasse

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

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