I have WebSocket server:
@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);
}
}
}
}
It notifies everyone connected except the one who sent the message.
And I have a client side:
@ClientEndpoint
public class WebSocketClient {
@OnMessage
public void onMessage (String message, Session session) {
System.out.println("[SERVER RESPONSE]: " + message);
MyJFrame.setButtonGrid(message);
}
}
My 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();
}
}
}
But in setButtonGrid
method I can't get the components of my JFrame, obviously because it's static method. But if it is not static, then I will not be able to call it from the class of my WebSocket client. So how do I change the text in the JFrame buttons when information comes from the WebSocket server?
The essential problem here is how do you have the visible GUI instance communicate with the socket client? One way to do this would be to pass an instance of the GUI into the web socket client via its constructor. So the web socket client would need a gui field and a constructor that takes the GUI as a parameter, and use this to set the field.
@ClientEndpoint
public class WebSocketClient {
private MyJFrame myJFrame; // add a GUI field
// add a constructor that allows passing in the GUI as a parameter
public WebSocketClient(MyJFrame myJFrame) {
this.myJFrame = myJFrame;
}
Then, when creating the session, call the constructor above and then call the clientManager.connectToServer(...)
method overload that accepts an object as first parameter, your WebSocketClient object, rather than takes the class as parameter:
MyJFrame myJFrame = new MyJFrame();
// ....
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);
Then, with this GUI instance, you could pass data from the client into the GUI, and visa-versa.
Say you had a GUI that looked like so:
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();
}
}
});
}
}
Your web socket client could look something like so:
@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);
}
}
Note:
setButtonGrid(...)
and that I call here, fromServer(...)
, to be a static method. It should instead be an instance method so that it can interact with your GUI instance.EventQueue.invokeLater(someRunnable)
but if I were doing this myself, I'd probably use a SwingWorker, passing the data in using the worker's publish/process method pair.