jPanel不会重绘,等待服务器消息

时间:2014-10-18 19:49:05

标签: java swing sockets

我正在创建一个带有套接字的连接四游戏:1个服务器正在运行,两个客户端应该连接以玩游戏。由于套接字(我认为),因为jPanel没有更新,我遇到了一些麻烦。

当游戏(客户端)启动时,您将获得一个带有IP地址输入框的jPanel和一个提交按钮。如果按下提交按钮,我想显示正在准备游戏的消息,并且它正在等待第二个玩家加入。

submitButton.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        if (!input.getText().equals("")) try {
            prefs.put("SavedIp", input.getText());
            errorLabel.setText("Preparing game and waiting for other players...");
            parentLayout.startGame(input.getText());
        } catch (SocketTimeoutException timeout) {
            errorLabel.setText("Server timed out.");
        } catch (IOException ioeException) {
            errorLabel.setText("Server not found!");
        } finally {
            setTheCursor(Cursor.getDefaultCursor());
        }
        else errorLabel.setText("Enter an IP adress");
    }
});    

然而,在startGame方法中,创建了一个新的GamePanel,并在该构造函数中创建了一个新的PlayField,并在该PlayField中创建了一个带有套接字的新连接。

连接后,它会运行方法checkForNextAction,以查看它是否收到来自服务器的消息。它一直运行该方法,直到服务器发送消息。

问题:当我按提交时,我看不到该消息。相反,它会挂起,直到第二个玩家加入,然后服务器发送一条消息,游戏可以启动并显示游戏板。我不能只是让消息立即更改为我设置的文本吗? jPanel可能不会更新,因为它正在运行方法并等待消息到来。

我在游戏中有类似的问题。当玩家将硬币放入列中时,此移动将被发送到服务器,但硬币不会在jPanel上绘制。相反,它会挂起/冻结。另一个客户端进行移动,只有第一个客户端的jPanel在第二次移动时使用第一次移动的硬币和来自另一个玩家的硬币进行更新。所以看来这一举动只有在其他球员采取行动后才会被吸引。

有没有人有想法?我尝试使用this.revalidate()这样的东西,但我似乎无法在执行startGame方法之前强制更新jPanel。

1 个答案:

答案 0 :(得分:3)

你的问题是一个Swing线程问题,因为你的代码等待,暂停Swing事件线程,冻结所有GUI绘图和用户交互。解决方案:使用后台线程(如SwingWorker)来等待您。请查看Concurrency in Swing


类似的东西,

  submitButton.addActionListener(new ActionListener() {
     @Override
     public void actionPerformed(ActionEvent e) {
        if (!input.getText().equals("")) {
           prefs.put("SavedIp", input.getText());
           errorLabel.setText("Preparing game and waiting for other players...");

           final ParentWorker parentWorker = new ParentWorker(input.getText());
           parentWorker.addPropertyChangeListener(new PropertyChangeListener() {

                    @Override
                    public void propertyChange(PropertyChangeEvent evt) {
                       if (SwingWorker.StateValue.DONE == evt.getNewValue()) {
                          setTheCursor(Cursor.getDefaultCursor());
                          try {
                             parentWorker.get();
                          } catch (InterruptedException | ExecutionException e) {
                             e.printStackTrace();
                             // here's where you check for your socket or io exceptions
                          }
                       }
                    }
                 });
           parentWorker.execute();
           // parentLayout.startGame(input.getText());
        } else {
           errorLabel.setText("Enter an IP adress");
        }
     }
  });

和...

class ParentWorker extends SwingWorker<Void, Void> {
  private String text;

  public ParentWorker(String text) {
     this.text = text;
  }

  @Override
  protected Void doInBackground() throws Exception {
     parentLayout.startGame(text);
     return null;
  }
}