JTextPane/JTextArea append() 随机工作
JTextPane/JTextArea append() working randomly
我在一个非常简单的 GUI 中有一个 JTextPane,我将其用作我用于学习的游戏的输出控制台 Java,我(尝试)将其与 window class,从另一个 class(程序本身)或命令 reader class 调用它。理论上它应该输出我输入的命令,并在下一行输出来自所述程序的输出。
打印方法(对 JTextArea 使用 append,或对 JTextPane 使用 getText() 和 setText())如果从它自己的 class 调用(打印使用的命令和“>”时)工作正常,但是,当从外部调用时,它会随机运行,有时会附加到 textArea 的最顶部,按预期工作,甚至复制其中的所有文本。
这是用于此目的的 GUI 代码。我敢肯定它并不完美甚至接近,但我才刚刚开始学习 GUI 的基础知识
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.text.DefaultCaret;
import graficos.VisorJugador;
public class test extends JFrame {
private static final long serialVersionUID = 1L;
private JPanel contentPane;
private String comando = "";
private JTextArea txp_Console;
private JScrollPane jsp_ConsoleScrollPanel;
private JLabel lbl_habitacion;
private VisorJugador[] jugadores;
/**
* Create the frame.
*/
public test() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 640, 480);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
createPanels();
}
public static void lanzar(test frame){
frame.setVisible(true);
}
private void createPanels(){
JPanel panelInferior = new JPanel();
JPanel panelCentral = new JPanel();
panelCentral.setLayout(new BorderLayout(0, 0));
crearInferior(panelInferior);
crearCentral(panelCentral);
contentPane.add(panelInferior, BorderLayout.SOUTH);
contentPane.add(panelCentral, BorderLayout.CENTER);
}
private void crearCentral(JPanel panelCentral) {
JLabel lbl_Consola = new JLabel("Consola");
txp_Console = new JTextArea();
jsp_ConsoleScrollPanel = new JScrollPane(txp_Console);
txp_Console.setEditable(true);
DefaultCaret caret = (DefaultCaret) txp_Console.getCaret();
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
panelCentral.add(lbl_Consola, BorderLayout.NORTH);
panelCentral.add(txp_Console, BorderLayout.CENTER);
}
private void crearInferior(JPanel panelInferior) {
JLabel lbl_QueHacer = new JLabel("Que quieres hacer?");
JButton btn_Enviar = new JButton("Hacer");
JTextField txt_consola = new JTextField();
btn_Enviar.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
comando = txt_consola.getText();
print("> " + txt_consola.getText());
txt_consola.setText("");
}
});
txt_consola.setColumns(10);
panelInferior.add(lbl_QueHacer, BorderLayout.NORTH);
panelInferior.add(txt_consola);
panelInferior.add(btn_Enviar);
}
public void print(String texto) {
String anterior = txp_Console.getText();
txp_Console.setText(anterior + texto);
}
}
每次我必须从程序中输出一些东西时,我都会调用 ventana.print(labels.getString(msg)),ventana 是一个新的 test 在其构造函数中创建的实例。我不了解线程,所以我没有任何处理它的方法,所以,据我所知,主线程上的一切都是 运行。
另外,这里有一些示例输出
No entiendo --From commands 2 and 3
No entiendo --From commands 2 and 3
Bienvenido al Mundo de Zuul! --Working output
El Mundo de Zuul es un juego de aventuras muy aburrido, pero interesante!. --Working output
Escribe 'ayuda' si necesitas ayuda. --Working output
Estas en el exterior de la entrada principal de la universidad --Working output
Salidas: este, sur, oeste --Working output
> 1 --Works as intended
No entiendo --Output for command 1
> 2 --Output at the top
> 3 --Output at the top
> 4 --No output, windows error sound
调试时我看到为 swing/awt 创建了一个线程,但我根本不了解线程,所以我只是希望我不需要它们。我也尝试过设置羽毛笔、移动滚动条、从命令中删除“/n”,但还没有成功。
您对线程的使用可能已关闭,但我们没有看到有问题的代码,因此很难判断。我要声明的一件事是,您应该始终在 Swing 事件线程上启动您的 GUI,并且应该努力在同一线程上对您的 GUI 进行更改。
您可以对 print 方法进行的一项更改是测试您是否在 Swing 事件线程上,如果是,则将传入的文本附加到 JTextArea。如果没有,则使用 SwingUtilities 创建代码以在事件线程上将此更改排队,如下所示:
public void print(String texto) {
// String anterior = txp_Console.getText();
// txp_Console.setText(anterior + texto);
if (SwingUtilities.isEventDispatchThread()) {
// if on the Swing event thread, call directly
txp_Console.append(texto); // a simple append call is all that is needed
} else {
// else queue it onto the event thread
SwingUtilities.invokeLater(() -> txp_Console.append(texto));
}
}
请阅读 Lesson: Concurrency in Swing 以了解有关 Swing 线程的更多信息。
例如,假设我有这样一个 GUI:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
@SuppressWarnings("serial")
public class JuanjoTestPanel extends JPanel {
private static final int TA_ROWS = 25;
private static final int TA_COLS = 60;
private JTextArea textArea = new JTextArea(TA_ROWS, TA_COLS);
private JTextField textField = new JTextField(30);
private Action hacerAction = new HacerAction();
public JuanjoTestPanel() {
textArea.setFocusable(false);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
JScrollPane scrollPane = new JScrollPane(textArea);
textField.setAction(hacerAction);
JPanel bottomPanel = new JPanel();
bottomPanel.add(new JLabel("¿Que queres hacer?"));
bottomPanel.add(Box.createHorizontalStrut(5));
bottomPanel.add(textField);
bottomPanel.add(new JButton(hacerAction));
setLayout(new BorderLayout());
add(scrollPane);
add(bottomPanel, BorderLayout.PAGE_END);
}
public void printToWindow(final String text) {
if (SwingUtilities.isEventDispatchThread()) {
textArea.append("Console:" + text + "\n");
} else {
SwingUtilities.invokeLater(() -> textArea.append("Console:" + text + "\n"));
}
}
private class HacerAction extends AbstractAction {
public HacerAction() {
super("Hacer");
putValue(MNEMONIC_KEY, KeyEvent.VK_H);
}
@Override
public void actionPerformed(ActionEvent e) {
String text = "> " + textField.getText() + "\n";
textArea.append(text);
textField.selectAll();
textField.requestFocusInWindow();
}
}
}
您也可以通过调用它的 printToWindow(...)
方法从控制台写入它,如下所示:
import java.util.Scanner;
import javax.swing.*;
public class TestSwing2 {
private static final String EXIT = "exit";
public static void main(String[] args) {
// create window
final JuanjoTestPanel testPanel = new JuanjoTestPanel();
// launch it on the Swing event thread
SwingUtilities.invokeLater(() -> createAndShowGui(testPanel));
Scanner scanner = new Scanner(System.in);
String line = "";
while (!line.trim().equalsIgnoreCase(EXIT)) {
System.out.print("Enter text: ");
line = scanner.nextLine();
System.out.println("Line entered: " + line);
testPanel.printToWindow(line); // write to it
}
scanner.close();
System.exit(0);
}
private static void createAndShowGui(JuanjoTestPanel testPanel) {
JFrame frame = new JFrame("Test Swing2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(testPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
我在一个非常简单的 GUI 中有一个 JTextPane,我将其用作我用于学习的游戏的输出控制台 Java,我(尝试)将其与 window class,从另一个 class(程序本身)或命令 reader class 调用它。理论上它应该输出我输入的命令,并在下一行输出来自所述程序的输出。
打印方法(对 JTextArea 使用 append,或对 JTextPane 使用 getText() 和 setText())如果从它自己的 class 调用(打印使用的命令和“>”时)工作正常,但是,当从外部调用时,它会随机运行,有时会附加到 textArea 的最顶部,按预期工作,甚至复制其中的所有文本。
这是用于此目的的 GUI 代码。我敢肯定它并不完美甚至接近,但我才刚刚开始学习 GUI 的基础知识
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.text.DefaultCaret;
import graficos.VisorJugador;
public class test extends JFrame {
private static final long serialVersionUID = 1L;
private JPanel contentPane;
private String comando = "";
private JTextArea txp_Console;
private JScrollPane jsp_ConsoleScrollPanel;
private JLabel lbl_habitacion;
private VisorJugador[] jugadores;
/**
* Create the frame.
*/
public test() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 640, 480);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
createPanels();
}
public static void lanzar(test frame){
frame.setVisible(true);
}
private void createPanels(){
JPanel panelInferior = new JPanel();
JPanel panelCentral = new JPanel();
panelCentral.setLayout(new BorderLayout(0, 0));
crearInferior(panelInferior);
crearCentral(panelCentral);
contentPane.add(panelInferior, BorderLayout.SOUTH);
contentPane.add(panelCentral, BorderLayout.CENTER);
}
private void crearCentral(JPanel panelCentral) {
JLabel lbl_Consola = new JLabel("Consola");
txp_Console = new JTextArea();
jsp_ConsoleScrollPanel = new JScrollPane(txp_Console);
txp_Console.setEditable(true);
DefaultCaret caret = (DefaultCaret) txp_Console.getCaret();
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
panelCentral.add(lbl_Consola, BorderLayout.NORTH);
panelCentral.add(txp_Console, BorderLayout.CENTER);
}
private void crearInferior(JPanel panelInferior) {
JLabel lbl_QueHacer = new JLabel("Que quieres hacer?");
JButton btn_Enviar = new JButton("Hacer");
JTextField txt_consola = new JTextField();
btn_Enviar.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
comando = txt_consola.getText();
print("> " + txt_consola.getText());
txt_consola.setText("");
}
});
txt_consola.setColumns(10);
panelInferior.add(lbl_QueHacer, BorderLayout.NORTH);
panelInferior.add(txt_consola);
panelInferior.add(btn_Enviar);
}
public void print(String texto) {
String anterior = txp_Console.getText();
txp_Console.setText(anterior + texto);
}
}
每次我必须从程序中输出一些东西时,我都会调用 ventana.print(labels.getString(msg)),ventana 是一个新的 test 在其构造函数中创建的实例。我不了解线程,所以我没有任何处理它的方法,所以,据我所知,主线程上的一切都是 运行。
另外,这里有一些示例输出
No entiendo --From commands 2 and 3
No entiendo --From commands 2 and 3
Bienvenido al Mundo de Zuul! --Working output
El Mundo de Zuul es un juego de aventuras muy aburrido, pero interesante!. --Working output
Escribe 'ayuda' si necesitas ayuda. --Working output
Estas en el exterior de la entrada principal de la universidad --Working output
Salidas: este, sur, oeste --Working output
> 1 --Works as intended
No entiendo --Output for command 1
> 2 --Output at the top
> 3 --Output at the top
> 4 --No output, windows error sound
调试时我看到为 swing/awt 创建了一个线程,但我根本不了解线程,所以我只是希望我不需要它们。我也尝试过设置羽毛笔、移动滚动条、从命令中删除“/n”,但还没有成功。
您对线程的使用可能已关闭,但我们没有看到有问题的代码,因此很难判断。我要声明的一件事是,您应该始终在 Swing 事件线程上启动您的 GUI,并且应该努力在同一线程上对您的 GUI 进行更改。
您可以对 print 方法进行的一项更改是测试您是否在 Swing 事件线程上,如果是,则将传入的文本附加到 JTextArea。如果没有,则使用 SwingUtilities 创建代码以在事件线程上将此更改排队,如下所示:
public void print(String texto) {
// String anterior = txp_Console.getText();
// txp_Console.setText(anterior + texto);
if (SwingUtilities.isEventDispatchThread()) {
// if on the Swing event thread, call directly
txp_Console.append(texto); // a simple append call is all that is needed
} else {
// else queue it onto the event thread
SwingUtilities.invokeLater(() -> txp_Console.append(texto));
}
}
请阅读 Lesson: Concurrency in Swing 以了解有关 Swing 线程的更多信息。
例如,假设我有这样一个 GUI:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
@SuppressWarnings("serial")
public class JuanjoTestPanel extends JPanel {
private static final int TA_ROWS = 25;
private static final int TA_COLS = 60;
private JTextArea textArea = new JTextArea(TA_ROWS, TA_COLS);
private JTextField textField = new JTextField(30);
private Action hacerAction = new HacerAction();
public JuanjoTestPanel() {
textArea.setFocusable(false);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
JScrollPane scrollPane = new JScrollPane(textArea);
textField.setAction(hacerAction);
JPanel bottomPanel = new JPanel();
bottomPanel.add(new JLabel("¿Que queres hacer?"));
bottomPanel.add(Box.createHorizontalStrut(5));
bottomPanel.add(textField);
bottomPanel.add(new JButton(hacerAction));
setLayout(new BorderLayout());
add(scrollPane);
add(bottomPanel, BorderLayout.PAGE_END);
}
public void printToWindow(final String text) {
if (SwingUtilities.isEventDispatchThread()) {
textArea.append("Console:" + text + "\n");
} else {
SwingUtilities.invokeLater(() -> textArea.append("Console:" + text + "\n"));
}
}
private class HacerAction extends AbstractAction {
public HacerAction() {
super("Hacer");
putValue(MNEMONIC_KEY, KeyEvent.VK_H);
}
@Override
public void actionPerformed(ActionEvent e) {
String text = "> " + textField.getText() + "\n";
textArea.append(text);
textField.selectAll();
textField.requestFocusInWindow();
}
}
}
您也可以通过调用它的 printToWindow(...)
方法从控制台写入它,如下所示:
import java.util.Scanner;
import javax.swing.*;
public class TestSwing2 {
private static final String EXIT = "exit";
public static void main(String[] args) {
// create window
final JuanjoTestPanel testPanel = new JuanjoTestPanel();
// launch it on the Swing event thread
SwingUtilities.invokeLater(() -> createAndShowGui(testPanel));
Scanner scanner = new Scanner(System.in);
String line = "";
while (!line.trim().equalsIgnoreCase(EXIT)) {
System.out.print("Enter text: ");
line = scanner.nextLine();
System.out.println("Line entered: " + line);
testPanel.printToWindow(line); // write to it
}
scanner.close();
System.exit(0);
}
private static void createAndShowGui(JuanjoTestPanel testPanel) {
JFrame frame = new JFrame("Test Swing2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(testPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}