2014-10-02 19 views
0

我想運行一個簡單的遊戲,其中有一個服務器和一個客戶端互相對話來執行更新,目前我在服務器和客戶端之間沒有做太多的工作,只是發送一些毫無意義的東西。我的問題是我的'clientframe'延伸JFrame,當我嘗試在我的'slave'(客戶端)的run方法中創建一個新的clientframe時,它不能正確顯示。當我使用自己的主要方法運行時,我的客戶機工作正常,但由於某種原因,當我嘗試在從機類的運行方法內創建一個新的客戶機時,會在頂部畫一個帶有白色矩形的黑色屏幕。我意識到這是不夠的代碼來運行它,我花了幾個小時試圖調試它,但我卡住了,謝謝!JFrame在一個線程內沒有正常運行

public final class Slave extends Thread { 


private final Socket socket; 
private NetworkHandler game;  
private DataOutputStream output; 
private DataInputStream input; 
private int uid; 
private int totalSent; 
private List<Integer> numbers = new ArrayList<Integer>() ; 

private Update lastSentUpdate; 

/** 
* Construct a slave connection from a socket. 
* 
* @param socket 
*/ 
public Slave(Socket socket) {    
    this.socket = socket;    
} 

public void run() { 
    try {  

     output = new DataOutputStream(socket.getOutputStream()); 
     input = new DataInputStream(socket.getInputStream()); 


      game = new NetworkHandler(NetworkHandler.Type.CLIENT); 
      PlayableCharacter ch = game.getGameUtill().findCharacter(uid); 

      ClientFrame frame = new ClientFrame(game, uid, true, ch); 

      while(true){ 
       uid = input.readInt();  
       // now read the other players IDs 
       int noPlayers = input.readInt(); 
       List<Integer> playerIds = new ArrayList<Integer>(); 

       for(; noPlayers>0; noPlayers--){ 
        playerIds.add(input.readInt()); 
       } 

       numbers = playerIds; 
      } 
     socket.close(); // release socket ... v.important! 
    } catch(IOException e) { 
     System.err.println("I/O Error: " + e.getMessage()); 
     e.printStackTrace(System.err); 
    } 
} 

public List<Integer> getNumbers(){ 
    return numbers; 
} 

public int getUID(){ 
    return uid; 
} 
} 


public class ClientFrame extends JFrame implements KeyListener { 

private static final double FRAMEHEIGHTMODIFIER = 600.0/768; 
private static final double ASPECTRATIO = 2; 

private GameRunner runner; 
private int clientsUID; 
private RenderPanel renderPanel; 
private boolean isClient; 
private StatPanel statPanel; 
private Dimension windowSize; 

public ClientFrame(GameRunner network, int UID, boolean isClient, 
     PlayableCharacter character) { 
    super("Cat and Mouse"); 
    this.setLocation(new Point(50, 50)); 
    this.setDefaultCloseOperation(EXIT_ON_CLOSE); 
    this.setResizable(false); 
    this.setVisible(true); 
    System.out.println("done setup"); 
    this.setDimensions(); 
    this.setLayout(null); 
    this.addKeyListener(this); 
    this.addPanels(character); 
    this.clientsUID = UID; 
    this.runner = network; 
    this.isClient = isClient; 
    this.setup(); 
} 

private void setDimensions() { 
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 
    if (screenSize == null) { 
     System.out.println("screenSize is null"); 
    } 
    System.out.println(screenSize.getHeight()); 
    int windowHeight = (int) (screenSize.getHeight() * FRAMEHEIGHTMODIFIER); 
    int windowWidth = (int) (windowHeight * ASPECTRATIO); 
    System.out.printf("Width: %d | Height: %d", windowWidth, windowHeight); 
    windowSize = new Dimension(windowWidth, windowHeight); 
    this.setSize(windowSize); 
    this.setPreferredSize(windowSize); 
    System.out.println("dimensions set"); 
} 

private void addPanels(PlayableCharacter character) { 
    renderPanel = new RenderPanel(windowSize, this); 

    // Create dimensions 
    int panelHeight = (int) (1.0/2 * windowSize.getHeight()); 
    int statPanelWidth = (int) (1.0/6 * windowSize.getWidth()); 
    int invPanelWidth = (int) (1.0/24 * windowSize.getWidth()); 

    Dimension statPanelDim = new Dimension(statPanelWidth, panelHeight); 
    Dimension invPanelDim = new Dimension(invPanelWidth, panelHeight); 

    // Create locations 
    int invLocationX = (int) (1.0/60 * windowSize.getWidth()); 
    int invPanelLocationY = (int) (3.0/8 * windowSize.getHeight()); 
    int statLocationX = (int) (49.0/60 * windowSize.getWidth()); 
    int statPanelLocationY = (int) (7.0/16 * windowSize.getHeight()); 

    InventoryPanel invPanel = new InventoryPanel(character, invPanelDim); 
    invPanel.setLocation(invLocationX, invPanelLocationY); 
    invPanel.setSize(invPanelDim); 
    invPanel.setPreferredSize(invPanelDim); 

    statPanel = new StatPanel(character); 
    statPanel.setLocation(statLocationX, statPanelLocationY); 
    statPanel.setSize(statPanelDim); 
    statPanel.setPreferredSize(statPanelDim); 

    this.add(invPanel); 
    this.add(statPanel); 
    this.add(renderPanel); 
    System.out.println("panel set fine"); 
} 

// @Override 
// public void redraw(){ 
// 
// } 

/** 
* NOTE: may need to check when moving if moved to another room!! TODO 
*/ 
@Override 
public void keyPressed(KeyEvent key) { 
} 

@Override 
public void keyReleased(KeyEvent arg0) { 
    // TODO Auto-generated method stub 

} 

@Override 
public void keyTyped(KeyEvent arg0) { 
    // TODO Auto-generated method stub 

} 

public static void main(String[] args) { 
    ArrayList<GameItem> items = new ArrayList<GameItem>(); 
    items.add(new Food(2, 30)); 
    items.add(new Key(3)); 
    items.add(new Food(2, 30)); 

    PlayableCharacter character = new PlayableCharacter(1, null, " ", 3, 5, 
      items); 
    new ClientFrame(null, 0, false, character); 
} 


} 
+0

Swing線程違規,null佈局和鍵監聽器都將會對你有用。在Swing,SwingWorker中搜索併發性,爲輸入解決方案佈置容器和密鑰綁定 – MadProgrammer 2014-10-02 20:52:42

回答

4

你不能做你想做的事情。

任何GUI操作必須發生在GUI(主)線程上,並且不能發生在後臺線程上。您應該使用SwingWorker,後者具有在後臺線程上運行後臺操作的方法,然後在GUI線程上運行的末尾調用done()方法,以基於後臺計算的結果處理GUI更新。

+2

有關更多詳細信息,請參見[併發性](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/)。 – 2014-10-02 10:22:46

+0

雖然我並沒有改變這個奴隸類的框架,但是我把它放在哪裏並不重要,我只是想在不破壞的情況下同時運行奴隸和框架。如果我使用SwingWorker(我不太瞭解它,但我一直在嘗試),但我不確定在這種情況下我將如何使用它,因爲奴隸實際上沒有對框架做任何事情,除了做它?但即使當我在其他地方創建框架時,如果我在程序的某個地方創建了一個奴隸,它也會中斷 – 2014-10-02 10:59:03

+0

@Francinebc您需要在GUI線程上創建'JFrame',然後在GUI線程以外的任何地方都不能訪問它。任何時候你從另一個線程觸摸它,都會造成麻煩。 – 2014-10-02 11:00:39