GUI未按预期更新/控制流问题

时间:2013-05-22 01:40:36

标签: java swing sockets concurrency event-dispatch-thread

我正在为学校项目制作网络战舰游戏。 GUI具有JButtons网格作为游戏板。当用户点击按钮时,它会调用下面的sendShot()方法。此方法将其镜头发送到远程计算机,远程计算机检查其是命中还是未命中并返回结果。然后,第一台机器接收该结果并相应地更新其GUI。我在下面的代码是这样做的,但我的问题是GUI在其他机器发送下一个镜头之前没有更新。我猜这是因为我在recieveShot()方法中调用sendShot(),但我不清楚为什么,因为更新GUI的方法(gp.ob.updateBoard(sr)) )在receiveShot()之前调用。我在这里误解了什么?

此外,我觉得我的基本程序流方法存在缺陷,并且不应该从receiveShot()方法调用sendShot()。这个方案有没有明显的替代方案?

void sendShot(ShotAttempt sa){

    try {
       oos.writeObject(sa);
       oos.flush();
       System.out.println("shot fired");
       ShotResult sr = (ShotResult)ois.readObject();
       gp.ob.updateBoard(sr); 
    } catch (IOException | ClassNotFoundException e) {
        System.out.println(e.printStackTrace());}
      receiveShot();
}

void receiveShot(){
    try{
    ShotAttempt sa = (ShotAttempt)ois.readObject();
    ShotResult sr = gp.db.acceptShot(sa);
    oos.writeObject(sr);
    oos.flush();
    } catch (IOException | ClassNotFoundException e){e.printStackTrace();}
}

1 个答案:

答案 0 :(得分:2)

  

在其他机器发送下一个镜头之前,GUI才会更新。我猜这是因为我在sendShot()方法中调用recieveShot(),但我不是100%清楚为什么,因为更新GUI的方法(gp.ob.updateBoard(sr)) )在receiveShot()之前调用。

receiveShot()方法阻止Swing事件调度线程或EDT。由于此线程负责所有Swing图形,用户交互和Swing事件处理,因此即使它们在调用receiveShot()方法之前排队,也不会处理在事件线程上排队等待处理的Runnables。它们只能在线程被解除阻塞时进行处理,这将在您收到镜头后进行处理。

建议:

  • 您应该在后台线程上进行所有套接字通信。
  • 我会创建程序状态,也许是由一个枚举,称为State,并给它至少两个可能的值,SHOOTING AND RECEIVING。
  • 在发送状态后将状态设置为State.RECEIVING。
  • 收到镜头后回到State.SHOOTING。
  • 不允许播放器在接收状态下发送镜头。这样,您的代码就不需要阻止方法来阻止用户进行拍摄。
  • 你也可以将END_GAME作为你的一个州。
  • 我会给我的班级setState(State state)方法。
  • 在这种方法中,我可以根据新状态启用/禁用我的拍摄按钮。
  • 您需要一个后台线程,可能是SwingWorker,不断运行,在套接字上侦听消息。当此线程收到已被拍摄的信息时,它会通过调用setState(newState)来更新程序的状态。
  • 我会注意在Swing事件线程上调用setState,以便状态更改全部由一个线程完成。
  • 然后我会在一个单独的背景线程上调用射击,但只有一个才能进行射击。它不会持续运行。

有关Swing Event Dispatch Thread的更多信息,请查看Concurrency in Swing