2014-10-02 38 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