【问题标题】:Can't append JTextArea无法附加 JTextArea
【发布时间】:2013-11-26 05:10:34
【问题描述】:

大家好,我正在尝试编写客户端-服务器井字游戏,但遇到了一些问题。我真的迷路了,花了 8 个小时试图找出问题所在。目前我正在尝试在我的用户界面中向 JTextArea 附加一条消息。但它不想向文本区域添加任何内容。任何帮助将不胜感激。

public class GameUI extends javax.swing.JFrame{
    /**
     * The circle icon
     */
    private ImageIcon circle = new ImageIcon("data/tile-05.png");

    /**
     * The cross icon
     */
    private ImageIcon cross = new ImageIcon("data/tile-03.png");

    /**
     * keeps track of whose turn it is
     */
    private int turn = 1;

    /**
     * Where the hear of the game runs
     */
    private Client game;

    /**
     * This is an 2d array that stores all the buttons
     */
    JButton[][] buttons = new JButton[3][3];

    /**
     * Class constructor Creates new form GameUI
     */
    public GameUI() {
        startGame("Tic Tac");
        storeButtons();
    }

    public void connectionError(String message) {
        JOptionPane.showMessageDialog(rootPane, message, "Tic Tac Toe", 0);
    }

    private void startGame(String message) {
        String host, login;
        int temp = 0;

        JTextField hostText = new JTextField();
        JTextField loginText = new JTextField();

        Object[] info = {"Host: ", hostText, "login ID: ", loginText};

        temp = JOptionPane.showConfirmDialog(rootPane, info, message, JOptionPane.OK_CANCEL_OPTION);

        while (true) {
            try {
                if (temp == JOptionPane.OK_OPTION) {
                    host = hostText.getText();
                    login = loginText.getText();

                    game = new Client(login, host, 5555, this); //Initializes the game
                    initComponents();
                    break;
                } else if (temp == JOptionPane.CANCEL_OPTION || temp == JOptionPane.CLOSED_OPTION) {
                    System.exit(0);
                }
            } catch (IOException e2) {
                connectionError("Can't connect to the game server!");
                System.exit(0);
            }
        }
        //Scrubs memory for more RAM :)
        login = null;
        host = null;

    }

    private void storeButtons() {
        buttons[0][0] = btnTicTac1;
        buttons[0][1] = btnTicTac2;
        buttons[0][2] = btnTicTac3;
        buttons[1][0] = btnTicTac4;
        buttons[1][1] = btnTicTac5;
        buttons[1][2] = btnTicTac6;
        buttons[2][0] = btnTicTac7;
        buttons[2][1] = btnTicTac8;
        buttons[2][2] = btnTicTac9;
    }

    private void btnOpponentSendActionPerformed(java.awt.event.ActionEvent evt) {                                                
        String message = txtOpponentMessage.getText();
        game.handleMessageFromGameUI("#Opponent " + message); //Specified the game text area
        txtOpponentMessage.setText("");
    }                                               

    private void btnLobbySendActionPerformed(java.awt.event.ActionEvent evt) {                                             
        String message = txtLobbyMessage.getText();
        game.handleMessageFromGameUI("#lobby " + message); //Specified the lobby text area
        txtLobbyMessage.setText("");
    }                                                

    public void setTurn(int value) {
        turn = value;
    }

    public void appendLobbyArea(String message) {
        txtLobbyTextArea.append(message);
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {

                GameUI cgui = new GameUI();
                cgui.setVisible(true);
            }
        });

    }

    // Variables declaration - do not modify                     
    private javax.swing.JButton btnLobbySend;
    private javax.swing.JButton btnOpponentSend;
    private javax.swing.JButton btnTicTac1;
    private javax.swing.JButton btnTicTac2;
    private javax.swing.JButton btnTicTac3;
    private javax.swing.JButton btnTicTac4;
    private javax.swing.JButton btnTicTac5;
    private javax.swing.JButton btnTicTac6;
    private javax.swing.JButton btnTicTac7;
    private javax.swing.JButton btnTicTac8;
    private javax.swing.JButton btnTicTac9;
    private javax.swing.JComboBox jComboBox1;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JScrollPane jScrollPane4;
    private javax.swing.JLabel lblOpponentSelect;
    private javax.swing.JList txtClientList;
    private javax.swing.JTextArea txtGameTextArea;
    private javax.swing.JTextField txtLobbyMessage;
    private javax.swing.JTextArea txtLobbyTextArea;
    private javax.swing.JTextField txtOpponentMessage;
    // End of variables declaration                   

    public void display(String message) {
        System.out.println(message);
    }
}

下一部分是中间人类。所有消息都通过这个类进行操作。

public class Client extends AbstractClient {

/**
 * GameUI Object. Used to communicate from the game to the end user
 */
private GameUI gameUI;

/**
 * This keeps track of whose turn it is. Defaults to x.
 */
private int turn = 1;

public Client(String userID, String host, int port, GameUI gameUI) throws IOException {
    super(host, port);
    this.gameUI = gameUI;
    openConnection();
    sendToServer("#login " + "<" + userID + ">");
}

@Override
public void handleMessageFromServer(Object msg) {
    while (isConnected()) {
        if (msg.toString().startsWith("#")) {
            doFunction(msg); 
        } else {

        }
    }
}

public void handleMessageFromGameUI(String message) {
    try {
    sendToServer(message);
    } catch (IOException e) {
        gameUI.display("Can't send message to server");
        System.exit(0);
    }
}

private void doFunction(Object msg) {
    if (msg.toString().startsWith("#connectedClient")) {
        gameUI.appendLobbyArea(msg.toString().substring(17) + " connected");
    } else if (msg.toString().startsWith("#disconnectedClient")) {
        gameUI.appendLobbyArea(msg.toString().substring(20) + " disconnected");
    } else if (msg.toString().startsWith("#lobby")) {
        gameUI.appendLobbyArea(msg.toString().substring(7)); //Add client username
    }
}

}

【问题讨论】:

  • 如需尽快获得更好的帮助,请发帖SSCCE

标签: java swing netbeans client-server tic-tac-toe


【解决方案1】:

乍一看...

你通过调用...启动程序

public static void main(String args[]) {
    /* Create and display the form */
    java.awt.EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {

            GameUI cgui = new GameUI();
            cgui.setVisible(true);
        }
    });

}

调用...

public GameUI() {
    startGame("Tic Tac");
    storeButtons();
}

调用...

private void startGame(String message) {
    String host, login;
    int temp = 0;

    JTextField hostText = new JTextField();
    JTextField loginText = new JTextField();

    Object[] info = {"Host: ", hostText, "login ID: ", loginText};

    temp = JOptionPane.showConfirmDialog(rootPane, info, message, JOptionPane.OK_CANCEL_OPTION);

    while (true) {
        try {
            if (temp == JOptionPane.OK_OPTION) {
                host = hostText.getText();
                login = loginText.getText();

                game = new Client(login, host, 5555, this); //Initializes the game
                initComponents();
                break;
            } else if (temp == JOptionPane.CANCEL_OPTION || temp == JOptionPane.CLOSED_OPTION) {
                System.exit(0);
            }
        } catch (IOException e2) {
            connectionError("Can't connect to the game server!");
            System.exit(0);
        }
    }
    //Scrubs memory for more RAM :)
    login = null;
    host = null;

}

这一切都在哪里停止......

我的第一个想法是,“您正在与事件调度线程之外的 UI 组件进行交互”,但是当我回溯调用堆栈时,我发现您实际上完全停止了事件调度线程的运行......

基本上。 Swing 是一个单线程环境,所有事件都由一个线程处理,称为 Event Dispatching Thread,它的工作显然是调度所有进入您的应用程序的事件,包括绘制请求。

任何阻止此线程运行的操作(如无限 while 循环和阻塞 I/O、锁定 Socket 通信)都将阻止它处理任何事件请求,包括绘制请求。

您还需要确保与 UI 的所有交互都是在 EDT 的上下文中完成的。这意味着您不应该尝试从除 EDT 之外的任何线程更新或修改任何 UI 组件。

根据您正在尝试做的事情,您最好使用SwingWorker 之类的东西。

它能够在后台执行长时间运行的任务(如Socket comms),同时提供将更新同步回 EDT 的简单功能

查看Concurrency in Swing了解更多详情

【讨论】:

  • 好的,如果我理解正确,我必须为我的 startGame(String message) 方法使用 SwingWorker,以便 EDT 可以继续运行而不会被我的 while(true) 循环中断?
  • 您还需要更改程序的运行方式,因为您不应该在 EDT 之外对 UI 进行修改。这意味着,您不能简单地将startGame 的内容移动到SwingWorker,因为它只会产生更多问题。您需要考虑如何弥合线程(SwingWorker)和 UI 之间的差距
  • 我不知道该怎么做。我得到了一个框架,由于它的限制,我可以修改 UI 的唯一方法是从我的 Client 类。因此,为什么我要这样做。很抱歉,如果这很痛苦。
  • 是的,但是您的应用程序知道需要运行一个单独的线程来读取和写入Socket。这意味着您需要设计将更新从 Socket 同步到 UI 并将更新从客户端获取到 Thread 的机制。如果SwingWorker 是限制性的,您也可以寻找SwingUtilities.invokeLater...
猜你喜欢
  • 1970-01-01
  • 2012-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多