更新 JTextArea 的问题

Problems with updating JTextArea

我正在编写一个带有 JTextArea 的简单纸牌游戏 GUI 来显示正在发生的事情以及谁放置了哪张纸牌等等。布局完成后,我添加了一个方法,将文本逐字符追加到JTextArea中,这样书写效果很好。我有一个 class 用于创建 window 和 GUI,还有一个 class 用于游戏和 TextArea 的输出。

但这仅适用于初始化游戏。之后,玩家必须通过按下按钮来选择一张牌,当他这样做时,我会在游戏对象中调用一个方法,以便它继续进行。这里的问题是它一直等到按下按钮的 actionEvent 被执行,然后用游戏处理的所有文本更新 TextArea,而不是逐个字符地更新它。仅在每个字符后添加 textArea.update(... 并不能解决问题,因为该区域开始闪烁。

这是我的 window class:

import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingConstants;
import javax.swing.border.LineBorder;
import javax.swing.JTable;
import javax.swing.border.MatteBorder;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.awt.event.ActionEvent;
import javax.swing.JTextField;
import javax.swing.JPanel;
import java.awt.ComponentOrientation;


public class window {

    private JFrame frmStinkt;
    private JLabel label;
    private JTextArea textArea;
    private JTable table;
    private static ArrayList<JButton> buttons = new ArrayList<JButton>();
    private JTextField textField;
    private static WindowGame newGame;
    private static int test = 0;

/**
 * Launch the application.
 */
public static void main(String[] args)
{
    window window = new window(104, 4);
    window.frmStinkt.setVisible(true);
    newGame = new WindowGame(104, 4, window.textArea, window.table);
    newGame.initGame();
    setButtonNames(newGame.players.get(0).cards);
    window.enableButtons();
}

/**
 * Create the application.
 */
public window(int numberOfCards, int numberOfRows)
{
    initialize();
}

/**
 * Initialize the contents of the frame.
 */


private void initialize() {
    Font defaultFont = new Font("Gill Sans MT",Font.BOLD,14);

    frmStinkt = new JFrame();
    frmStinkt.setTitle("6 STINKT!");
    frmStinkt.getContentPane().setForeground(Color.GREEN);
    frmStinkt.getContentPane().setFocusTraversalPolicyProvider(true);
    frmStinkt.getContentPane().setBackground(Color.BLACK);
    frmStinkt.setBounds(400, 200, 600, 450);
    frmStinkt.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frmStinkt.getContentPane().setLayout(null);

    JScrollPane scrollPane = new JScrollPane();
    scrollPane.setBorder(null);
    scrollPane.setBounds(83, 18, 420, 130);
    frmStinkt.getContentPane().add(scrollPane);

    textArea = new JTextArea();
    textArea.setBorder(new LineBorder(new Color(0, 255, 0), 2, true));
    textArea.setEditable(false);
    scrollPane.setViewportView(textArea);
    textArea.setWrapStyleWord(true);
    textArea.setForeground(Color.GREEN);
    textArea.setBackground(Color.BLACK);
    textArea.setLineWrap(true);
    textArea.setFont(new Font("Gill Sans MT", Font.BOLD, 13));

    label = new JLabel("CARDS");
    label.setEnabled(false);
    label.setHorizontalAlignment(SwingConstants.CENTER);
    label.setForeground(Color.GREEN);
    label.setBackground(Color.DARK_GRAY);
    label.setFont(defaultFont);
    label.setBounds(254, 264, 78, 23);
    frmStinkt.getContentPane().add(label);

    table = new JTable();
    table.setShowVerticalLines(false);
    table.setGridColor(new Color(0, 255, 0));
    table.setForeground(Color.GREEN);
    table.setBorder(new MatteBorder(1, 1, 1, 1, (Color) new Color(0, 255, 0)));
    table.setBackground(Color.BLACK);
    table.setBounds(165, 160, 255, 64);
    table.setFont(new Font("Gill Sans MT", Font.BOLD, 14));
    frmStinkt.getContentPane().add(table);

    textField = new JTextField();
    textField.setEditable(false);
    textField.setForeground(new Color(0, 255, 0));
    textField.setBackground(Color.DARK_GRAY);
    textField.setFont(new Font("Gill Sans MT", Font.BOLD, 14));
    textField.setBounds(277, 235, 32, 25);
    frmStinkt.getContentPane().add(textField, BorderLayout.CENTER);
    textField.setHorizontalAlignment(JTextField.CENTER);
    textField.setColumns(10);

    JPanel panel = new JPanel();
    panel.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
    panel.setBackground(Color.BLACK);
    panel.setBounds(10, 284, 564, 66);
    frmStinkt.getContentPane().add(panel);

    JButton button0 = new JButton("---");
    panel.add(button0);
    button0.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
    button0.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            button0.setVisible(false);
            test = buttons.indexOf(button0);
            textField.setText(Integer.toString(newGame.players.get(0).cards.get(0)));
            disableButtons();
            newGame.HumanTurn(test);
            buttons.remove(0);
        }
    });
    button0.setForeground(new Color(0, 255, 0));
    button0.setBackground(Color.decode("#000000"));
    button0.setFont(defaultFont);
    button0.setOpaque(true);
    button0.setRequestFocusEnabled(false);
    button0.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));

    buttons.add(button0);

    JButton button1 = new JButton("---");
    panel.add(button1);
    button1.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
    button1.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            newGame.HumanTurn(1);
            textField.setText(Integer.toString(newGame.players.get(0).cards.get(1)));
            disableButtons();
            panel.remove(button0);
        }
    });
    button1.setForeground(new Color(0, 255, 0));
    button1.setBackground(Color.decode("#000000"));
    button1.setFont(defaultFont);
    button1.setOpaque(true);
    button1.setRequestFocusEnabled(false);
    button1.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    buttons.add(button1);

    JButton button2 = new JButton("---");
    panel.add(button2);
    button2.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
    button2.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            newGame.HumanTurn(2);
            textField.setText(Integer.toString(newGame.players.get(0).cards.get(2)));
            disableButtons();
        }
    });
    button2.setForeground(new Color(0, 255, 0));
    button2.setBackground(Color.decode("#000000"));
    button2.setFont(defaultFont);
    button2.setOpaque(true);
    button2.setRequestFocusEnabled(false);
    button2.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    buttons.add(button2);

    JButton button3 = new JButton("---");
    panel.add(button3);
    button3.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
    button3.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            newGame.HumanTurn(3);
            textField.setText(Integer.toString(newGame.players.get(0).cards.get(3)));
            disableButtons();
        }
    });
    button3.setRequestFocusEnabled(false);
    button3.setForeground(new Color(0, 255, 0));
    button3.setBackground(Color.decode("#000000"));
    button3.setFont(defaultFont);
    button3.setOpaque(true);
    button3.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    buttons.add(button3);

    JButton button4 = new JButton("---");
    panel.add(button4);
    button4.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
    button4.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            newGame.HumanTurn(4);
            textField.setText(Integer.toString(newGame.players.get(0).cards.get(4)));
            disableButtons();
        }
    });
    button4.setRequestFocusEnabled(false);
    button4.setForeground(new Color(0, 255, 0));
    button4.setBackground(Color.decode("#000000"));
    button4.setFont(defaultFont);
    button4.setOpaque(true);
    button4.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    buttons.add(button4);

    JButton button5 = new JButton("---");
    panel.add(button5);
    button5.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
    button5.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            newGame.HumanTurn(5);
            textField.setText(Integer.toString(newGame.players.get(0).cards.get(5)));
            disableButtons();
        }
    });
    button5.setRequestFocusEnabled(false);
    button5.setForeground(new Color(0, 255, 0));
    button5.setBackground(Color.decode("#000000"));
    button5.setFont(defaultFont);
    button5.setOpaque(true);
    button5.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    buttons.add(button5);

    JButton button6 = new JButton("---");
    panel.add(button6);
    button6.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
    button6.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            newGame.HumanTurn(6);
            textField.setText(Integer.toString(newGame.players.get(0).cards.get(6)));
            disableButtons();
        }
    });
    button6.setRequestFocusEnabled(false);
    button6.setForeground(new Color(0, 255, 0));
    button6.setBackground(Color.decode("#000000"));
    button6.setFont(defaultFont);
    button6.setOpaque(true);
    button6.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    buttons.add(button6);

    JButton button7 = new JButton("---");
    panel.add(button7);
    button7.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
    button7.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            newGame.HumanTurn(7);
            textField.setText(Integer.toString(newGame.players.get(0).cards.get(7)));
            disableButtons();
        }
    });
    button7.setRequestFocusEnabled(false);
    button7.setForeground(new Color(0, 255, 0));
    button7.setBackground(Color.decode("#000000"));
    button7.setFont(defaultFont);
    button7.setOpaque(true);
    button7.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    buttons.add(button7);

    JButton button8 = new JButton("---");
    panel.add(button8);
    button8.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
    button8.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            newGame.HumanTurn(8);
            textField.setText(Integer.toString(newGame.players.get(0).cards.get(8)));
            disableButtons();
        }
    });
    button8.setRequestFocusEnabled(false);
    button8.setForeground(new Color(0, 255, 0));
    button8.setBackground(Color.decode("#000000"));
    button8.setFont(defaultFont);
    button8.setOpaque(true);
    button8.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    buttons.add(button8);

    JButton button9 = new JButton("---");
    panel.add(button9);
    button9.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
    button9.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            newGame.HumanTurn(9);
            textField.setText(Integer.toString(newGame.players.get(0).cards.get(9)));
            disableButtons();
        }
    });
    button9.setRequestFocusEnabled(false);
    button9.setForeground(new Color(0, 255, 0));
    button9.setBackground(Color.decode("#000000"));
    button9.setFont(defaultFont);
    button9.setOpaque(true);
    button9.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    buttons.add(button9);

    JButton random_1 = new JButton("RANDOM");
    random_1.setBounds(238, 361, 105, 25);
    frmStinkt.getContentPane().add(random_1);
    random_1.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
    random_1.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {
            int random = (int)(Math.random() * newGame.players.get(0).cards.size());
            newGame.HumanTurn(random);
            textField.setText(Integer.toString(newGame.players.get(0).cards.get(random)));
            disableButtons();
        }
    });
    random_1.setRequestFocusEnabled(false);
    random_1.setForeground(new Color(0, 255, 0));
    random_1.setBackground(Color.decode("#000000"));
    random_1.setFont(defaultFont);
    random_1.setOpaque(true);
    random_1.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    buttons.add(random_1);

    disableButtons();
}

public void enableButtons()
{
    for(int i=0; i<buttons.size(); i++)
        buttons.get(i).setEnabled(true);
    label.setEnabled(true);
}

public void disableButtons()
{
    for(int i=0; i<buttons.size(); i++)
        buttons.get(i).setEnabled(false);
    label.setEnabled(false);
}

public static void setButtonNames(ArrayList<Integer> cards)
{
    for(int i=0; i<buttons.size() - 1; i++)
        buttons.get(i).setText(cards.get(i).toString());
}
}

我了解到我可能可以通过使用 swingWorker 来解决这个问题。我找到了一个有用的进度条演示,但我不知道如何用我的方法使用它。我将不胜感激任何帮助。提前致谢!

这是它的样子:

这里是按钮按下和打印调用的方法:

public void HumanTurn(int cardIndex)
{
    print("Du hast " + players.get(0).cards.get(cardIndex) + " gewählt.", textSpeedNormal);
    next += 1;
    BotTurn();
}

public void print(String text, int speed)
{
    for(int i=0; i<text.length(); i++)
    {
        textArea.append(text.substring(i, (i+1)));
        try {
            Thread.sleep(speed);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    textArea.append("\n");
    textArea.setCaretPosition(textArea.getDocument().getLength());
}
Thread.sleep(speed);

不要使用 Thread.sleep(...)。

这会使 Event Dispatch Thread (EDT) 进入休眠状态,因此 GUI 无法响应事件或重新绘制自身。有关详细信息,请阅读 Concurrency 上的 Swing 教程。

而是使用 Swing Timer 来安排动画。 Swing Timer 取代了循环代码。每次计时器触发时,您都会执行一些操作,在本例中,向文本区域添加一个字符。

一种方法可能是将文本添加到 StringBuilder。然后,每次 Timer 触发时,您都会从 StringBuilder 中删除第一个字符并将其附加到文本区域。当 StringBuilder 为空时,您将停止计时器。