将数据从 WebSocket Server 设置到 JFrame 组件

问题描述 投票:0回答:1

我有 WebSocket 服务器:

@ServerEndpoint(value = "/demoApp")
public class MyWebSocketServer {
    @OnMessage
    public String onMessage (String message, Session session) throws IOException {
        for(Session session1 : Main.sessions){
            if(!session1.equals(session)){
                session1.getBasicRemote().sendText(message);
            }
        }
    }
}

它会通知除了发送消息的人之外所有已连接的人。

我有一个客户端:

@ClientEndpoint
public class WebSocketClient {
    @OnMessage
     public void onMessage (String message, Session session) {
        System.out.println("[SERVER RESPONSE]: " + message);
        MyJFrame.setButtonGrid(message);
    }
}

我的 JFrame:

public class MyJFrame extends javax.swing.JFrame {

    //some generated stuff

    public static void setButtonGrid(String message){
        Component[] components = this.getContentPane().getComponents();
        int i = 0;
        for(Component component : components){
            if(component instanceof JButton button){
                if("Restart".equals(button.getText())){
                    continue;
                }
                if(message.charAt(i) == '*'){
                    button.setText("");
                }
                else {
                    button.setText(message.charAt(i) + "");
                }
            }
        }
    }
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new TTTForm().setVisible(true);
            }
        });
        ClientManager clientManager = ClientManager.createClient();
        URI uri = null;
        try {
        uri = new URI("ws://localhost:8080/java/demoApp");
        session = clientManager.connectToServer(WebSocketClient.class, uri);
        } catch (URISyntaxException e) {
        e.printStackTrace();
        } catch (DeploymentException e) {
        e.printStackTrace();
        } catch (InterruptedException e) {
        e.printStackTrace();
        }
    }
}

但是在

setButtonGrid
方法中我无法获取 JFrame 的组件,显然因为它是静态方法。但如果它不是静态的,那么我将无法从 WebSocket 客户端的类中调用它。那么当信息来自 WebSocket 服务器时,如何更改 JFrame 按钮中的文本?

java swing jframe static-methods java-websocket
1个回答
0
投票

这里的本质问题是如何让可见的 GUI 实例与套接字客户端进行通信?实现此目的的一种方法是通过 GUI 的构造函数将 GUI 的实例传递到 Web 套接字客户端。然后,使用此 GUI 实例,您可以将数据从客户端传递到 GUI,反之亦然。

假设您有一个如下所示的 GUI:

public class MyJFrame extends javax.swing.JFrame {

    // ... code redacted ...

    public void fromServer(final String message) {
        // note that fromServer will of necessity be called *off* of the Swing event thread, the EDT
        // and so you will want to take steps to make sure that it is only used *on* this thread:
        EventQueue.invokeLater(new () -> {
            // use message from the GUI here
        });
    }
    
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(() -> {
            public void run() {
                MyJFrame myJFrame = new MyJFrame();

                ClientManager clientManager = ClientManager.createClient();
                URI uri = null;             
                try {                   
                    uri = new URI("ws://localhost:8080/java/demoApp");
                    // create our WebSocketClient, passing in the GUI
                    WebSocketClient webSocketClient = new WebSocketClient(myJFrame);
                    
                    // and then initiate the session using the above client
                    // This uses an overload of the connectToServer method that takes an object
                    session = clientManager.connectToServer(webSocketClient, uri);
                    myJFrame.setVisible(true); // start the GUI
                } catch (URISyntaxException e) {
                    e.printStackTrace();
                } catch (DeploymentException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

你的网络套接字客户端可能看起来像这样:

@ClientEndpoint
public class WebSocketClient {
    private MyJFrame myJFrame;
    
    public WebSocketClient(MyJFrame myJFrame) {
        this.myJFrame = myJFrame;
    }
    
    @OnMessage
     public void onMessage (String message, Session session) {
        System.out.println("[SERVER RESPONSE]: " + message);
        // MyJFrame.setButtonGrid(message); // don't call a static method but rather an instance method
        myJFrame.fromServer(message);
    }
}

注:

  • 您不希望您的通信方法(您称之为
    setButtonGrid(...)
    而我在这里称之为
    fromServer(...)
    )成为静态方法。它应该是一个实例方法,以便它可以与您的 GUI 实例交互。
  • Swing GUI 调用必须在 Swing 事件线程(称为事件调度线程或 EDT)上调用。否则,您的问题可能会引发不可预测的线程错误,或者可能冻结 GUI。在上面的代码中,我使用
    EventQueue.invokeLater(someRunnable)
    但如果我自己这样做,我可能会使用 SwingWorker,使用工作人员的发布/处理方法对传递数据。
  • 您还可以通过 setter 方法将客户端实例传递到 GUI,然后在 GUI 中调用客户端实例方法,从而让 GUI 将数据传回 Web 客户端。
  • 如果这是用于生产而不是简单的学术练习,我会使用 MVC 设计或类似的东西来放松 GUI 和程序逻辑之间的耦合。
  • 如果这是我的程序,我不会扩展 JFrame,因为没有绝对需要这样做,在这种情况下,使用组合确实比继承更好,但我试图不要使这个答案过于复杂.
© www.soinside.com 2019 - 2024. All rights reserved.