2009-12-14 18 views
0

我正在製作一個客戶端 - 服務器Java應用程序,它將是MV(C,P)。我目前的問題是,一旦客戶端獲得了一個Player對象,它需要告訴GUI該播放器已被更改,並且它應該更新GUI上的所有內容。 (不是太詳細,所以整個更新應該不會差)如何通過網絡傳遞Java序列化對象通知客戶端GUI的變化

/* 
* ClientGUI.java 
* 
* Created on Dec 10, 2009, 7:51:31 PM 
*/ 

package inequity; 

import java.io.IOException; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.net.Socket; 
import java.util.concurrent.PriorityBlockingQueue; 
import java.util.logging.Level; 
import java.util.logging.Logger; 

/** 
* 
* @author Administrator 
*/ 
public class ClientGUI extends javax.swing.JFrame 
{ 
    private Socket socClient; 
    private ObjectOutputStream socketOut; 
    private ObjectInputStream socketIn; 
    PriorityBlockingQueue<Command> clientQ = null; 
    private Player me; 

    public ClientGUI() 
    { 
    initComponents(); 
    setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE); 
    clientQ = new PriorityBlockingQueue<Command>(Server.CLIENT_QUEUE_SIZE, new CompObj()); 
    me = new Player(); 
    } 
    public void initPlayer(String name, String color) 
    { 
    me.name = name; 
    me.color = color; 
    } 

    public boolean connect(int port) 
    { 
    try 
    { 
     socClient = new Socket("127.0.0.1", port); 
     if(socClient.isConnected()) 
     System.out.println("Connected"); 

     socketOut = new ObjectOutputStream(socClient.getOutputStream()); 
     socketIn = new ObjectInputStream(socClient.getInputStream()); 

     socketOut.writeObject(new PlayerUpdate(me, 2)); 

     new ClientListener(socketIn).start(); 

    } 
    catch(Exception e) 
    { 
     try 
     { 
     if(socketOut != null) 
     { 
      socketOut.flush(); 
      socketOut.close(); 
     } 

     if(socketIn != null) 
     { 
      socketIn.close(); 
     } 

     System.out.println("Unable to connect"); 
     } 
     catch (IOException ex) 
     { 
     System.out.println("IOException caught"); 
     return false; 
     } 
    } 
    return true; 
    } 

    /** This method is called from within the constructor to 
    * initialize the form. 
    * WARNING: Do NOT modify this code. The content of this method is 
    * always regenerated by the Form Editor. 
    */ 
    @SuppressWarnings("unchecked") 
    // <editor-fold defaultstate="collapsed" desc="Generated Code">       
    private void initComponents() { 

    txtMsg = new javax.swing.JTextField(); 
    btnSend = new javax.swing.JButton(); 
    PlayerName = new javax.swing.JLabel(); 
    ID = new javax.swing.JLabel(); 
    chat = new javax.swing.JLabel(); 

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 

    txtMsg.setText("Test"); 
    txtMsg.setName("txtMsg"); // NOI18N 
    txtMsg.addActionListener(new java.awt.event.ActionListener() { 
     public void actionPerformed(java.awt.event.ActionEvent evt) { 
     txtMsgActionPerformed(evt); 
     } 
    }); 

    btnSend.setText("Send"); 
    btnSend.setName("btnSend"); // NOI18N 
    btnSend.addActionListener(new java.awt.event.ActionListener() { 
     public void actionPerformed(java.awt.event.ActionEvent evt) { 
     btnSendActionPerformed(evt); 
     } 
    }); 

    PlayerName.setText("N/A"); 
    PlayerName.setName("PlayerName"); // NOI18N 

    ID.setText("ID:"); 
    ID.setName("ID"); // NOI18N 

    chat.setText("Chatbox"); 
    chat.setName("chat"); // NOI18N 

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); 
    getContentPane().setLayout(layout); 
    layout.setHorizontalGroup(
     layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
     .addGroup(layout.createSequentialGroup() 
     .addContainerGap() 
     .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
      .addGroup(layout.createSequentialGroup() 
      .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
       .addComponent(btnSend, javax.swing.GroupLayout.DEFAULT_SIZE, 149, Short.MAX_VALUE) 
       .addComponent(txtMsg, javax.swing.GroupLayout.DEFAULT_SIZE, 149, Short.MAX_VALUE) 
       .addComponent(PlayerName, javax.swing.GroupLayout.DEFAULT_SIZE, 149, Short.MAX_VALUE)) 
      .addContainerGap()) 
      .addGroup(layout.createSequentialGroup() 
      .addComponent(ID) 
      .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 62, Short.MAX_VALUE) 
      .addComponent(chat) 
      .addGap(41, 41, 41)))) 
    ); 
    layout.setVerticalGroup(
     layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
     .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() 
     .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 
     .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) 
      .addComponent(ID) 
      .addComponent(chat)) 
     .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) 
     .addComponent(PlayerName) 
     .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) 
     .addComponent(txtMsg, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) 
     .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) 
     .addComponent(btnSend) 
     .addContainerGap()) 
    ); 

    pack(); 
    }// </editor-fold>       

    private void txtMsgActionPerformed(java.awt.event.ActionEvent evt) {          

    }          

    private void btnSendActionPerformed(java.awt.event.ActionEvent evt) {           
     try 
     { 
     if(socketOut != null) 
      socketOut.writeObject(new ChatCmd(txtMsg.getText(), 10)); 

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

    }          

    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String args[]) { 
     java.awt.EventQueue.invokeLater(new Runnable() { 
      public void run() 
      { 
       String name = ""; 
       String color = ""; 

       JoinGUI join = new JoinGUI(name, color); 
       ClientGUI client = new ClientGUI(); 
       client.initPlayer(name, color); 

       client.setVisible(join.prompt()); 
       client.connect(1345); 
      } 
     }); 
    } 

    // Variables declaration - do not modify      
    private javax.swing.JLabel ID; 
    private javax.swing.JLabel PlayerName; 
    private javax.swing.JButton btnSend; 
    private javax.swing.JLabel chat; 
    private javax.swing.JTextField txtMsg; 
    // End of variables declaration     


    // End of variables declaration 

    public class ClientListener extends Thread 
    { 
    private ObjectInputStream recieving; 
    public ClientListener(ObjectInputStream in) 
    { 
     recieving = in; 
    } 

    @Override 
    public void run() 
    { 
     Command cmd; 
     while(true) 
     { 
     try 
     { 
      cmd = (Command) recieving.readObject(); 
      clientQ.add(cmd); 
      //temp code! Put in clientProxy? Drop to clientQ? 
      clientQ.take().exec(me); 
      ID.setText("" + me.getID()); 
      PlayerName.setText("" + me.name); 
      chat.setText(me.latestChatMsg); 
     } 
     catch (InterruptedException ex) 
     { 
      Logger.getLogger(ClientGUI.class.getName()).log(Level.SEVERE, null, ex); 
     } 
     catch (IOException ex) 
     { 
      Logger.getLogger(ClientListener.class.getName()).log(Level.SEVERE, null, ex); 
     } 
     catch (ClassNotFoundException ex) 
     { 
      Logger.getLogger(ClientListener.class.getName()).log(Level.SEVERE, null, ex); 
     } 

     } 

    } 

    } 

} 

package inequity; 

import java.io.Serializable; 
import java.util.ArrayList; 

/** 
* 
* @author Administrator 
*/ 

public class Player implements Serializable 
{ 
    public ArrayList openHandShakes; 
    public String latestChatMsg; 
    private int ID; 
    public String name; 
    public String color; 

    public Player() 
    { 
    openHandShakes = new ArrayList(); 
    ID = -1; 
    name = ""; 
    color = ""; 
    } 
    public void setID(int id) 
    { 
    ID = id; 
    } 
    public int getID() 
    { 
    return ID; 
    } 
    public void openHandShake(int shakeID) 
    { 
    openHandShakes.add(shakeID); 
    } 
    public boolean closeHandShake(int shakeID) 
    { 
    return true; 
    } 

    public void latestChat(String message) 
    { 
    latestChatMsg = message; 
    } 

} 

package inequity; 

import javax.swing.Box; 
import javax.swing.JTextField; 

/** 
* 
* @author Administrator 
*/ 
public class JoinGUI extends javax.swing.JFrame 
{ 
    private JTextField nameBox; 
    private JTextField colorBox; 

    public JoinGUI(String name, String color) 
    { 
    //give back name and color to clientgui 
    nameBox = new JTextField("Enter Name"); 
    colorBox = new JTextField("Enter Color"); 
    Box inputMenu = Box.createVerticalBox(); 

    inputMenu.add(nameBox); 
    inputMenu.add(colorBox); 
    add(inputMenu); 
    } 
    public boolean prompt() 
    { 
    setVisible(false); 
    //wait for enter to be pressed then return true, as clientGUI is waiting to started 
    //then give name and color to client 
    return true; 
    } 
} 
/* 
* Server.java 
*/ 

package inequity; 

import java.util.logging.Level; 
import java.util.logging.Logger; 
import javax.swing.JFrame; 
import java.net.*; 
import java.util.concurrent.PriorityBlockingQueue; 

/** 
* The main class of the application. 
*/ 
public class Server extends JFrame 
{ 
    public static final int CLIENT_QUEUE_SIZE = 10; 
    public static final int SERVER_QUEUE_SIZE = 10; 

    public Server() 
    { 
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    } 

    public PlayerProxy wait4client(int playerID, ServerSocket server, PriorityBlockingQueue<Command> srvQ) 
    { 
    Socket incoming; 
    PriorityBlockingQueue<Command> clientQ = null; 
    Runnable rIn; 
    Runnable rOut; 
    Thread tIn = null; 
    Thread tOut = null; 

    try 
    { 
     incoming = server.accept(); 
     clientQ = new PriorityBlockingQueue<Command>(CLIENT_QUEUE_SIZE, new CompObj()); 

     rIn = new Net2QRunnable(playerID, incoming, srvQ); 
     rOut = new Q2NetRunnable(playerID, incoming, clientQ); 

     tIn = new Thread(rIn); 
     tOut = new Thread(rOut); 

     tIn.start(); 
     tOut.start();  
    } 
    catch (Exception e) 
    { 
     e.printStackTrace(); 
    } 
    clientQ.add(new HelloMsg()); 

    return new PlayerProxy(playerID, tIn, tOut, clientQ); 
    } 

    public static void main(String[] args) 
    { 
    PriorityBlockingQueue<Command> srvQ = new PriorityBlockingQueue<Command>(SERVER_QUEUE_SIZE, new CompObj()); 

    try 
    { 
     Game game = new Game(srvQ); 
     Server srv = new Server(); 
     ServerSocket server = new ServerSocket(1345); 

     srv.setVisible(true); 

     System.out.println("Lobby"); 
     while (game.numPlayers() < 2) 
     { 
     game.addPlayer(srv.wait4client(game.numPlayers(), server, srvQ)); 
     } 

     game.play(); 

     System.out.println("Game Finished"); 
    } 
    catch (SocketException e) 
    { 
     System.out.println("Socket already taken, exiting."); 
    } 
    catch (Exception ex) 
    { 
     Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex); 
    } 

    } 
} 

我可以提供完整的源代碼,如果你願意,但我認爲這是所有的需要。 再次,一個Player對象get被髮送到客戶端,它接受並將其Player對象設置爲接收到的對象。我希望客戶端播放器說:「嘿,GUI!我剛剛修改了,Lemme調用了一種更新方法來提取/解析我的所有數據!」

任何幫助,將不勝感激。

UPDATE:

public class ClientListener extends Thread 
    { 
    private ObjectInputStream recieving; 
    public ClientListener(ObjectInputStream in) 
    { 
     recieving = in; 
    } 

    @Override 
    public void run() 
    { 
     Command cmd; 
     while(true) 
     { 
     try 
     { 
      cmd = (Command) recieving.readObject(); 
      clientQ.add(cmd); 

      java.awt.EventQueue.invokeLater(new Runnable() 
      { 
      public void run() 
      { 
       try 
       { 
       clientQ.take().exec(me); 
       if(me.changed == true) 
        updateGUI(); 


       } 
       catch (Exception ex) 
       { 
       Logger.getLogger(ClientGUI.class.getName()).log(Level.SEVERE, null, ex); 
       } 
      } 
      }); 
     } 
     catch (Exception ex) 
     { 
      Logger.getLogger(ClientListener.class.getName()).log(Level.SEVERE, null, ex); 
     } 

     } 

    } 

    } 

好像應該是我想要的嗎?

回答

2

只需將您的更新代碼放入Runnable實例並將其傳遞到SwingUtilities.InvokeLater()即可。這會將您的可運行隊列放入事件調度隊列

或者您可以調用invokeAndWait來阻塞,直到更新完成。

如果您嘗試調用更新另一個線程中的Swing元素的代碼,它可能會導致其他代碼中的不穩定。

+0

因此,在ClientListener獲取數據後,請調用InvokeLater/InvokeAndWait調用? – 2009-12-15 02:04:28

相關問題