[英]How to properly use input from an Actionlistener event
我已经学习java几个月了,我遇到了一个问题,就是我使用actionlistener的输入方式。 会发生什么,我有一个方法,允许用户在文本框中输入内容并输入它。 完成后,字符串将被写入我的类中的公共静态字段,其值将从输入方法中获取并返回值,并将字段设置回空字符串。 它工作正常,但有时控制台会抛出无害的nullpointerexception。 从我所做的所有研究中,我发现这两个线程正在引起某种冲突,但我还没有真正弄清楚为什么会发生这种情况或如何解决它。
输入时有时会出现错误。
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at javax.swing.text.PlainView.updateMetrics(Unknown Source)
at javax.swing.text.PlainView.lineToRect(Unknown Source)
at javax.swing.text.PlainView.modelToView(Unknown Source)
at javax.swing.text.FieldView.modelToView(Unknown Source)
at javax.swing.plaf.basic.BasicTextUI$RootView.modelToView(Unknown Source)
at javax.swing.plaf.basic.BasicTextUI.modelToView(Unknown Source)
at javax.swing.text.DefaultCaret.repaintNewCaret(Unknown Source)
at javax.swing.text.DefaultCaret$1.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$200(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
我的主类包挂起;
public class Main
{
public static void main(String[] args)
{
GUIHandler gui = new GUIHandler();
gui.handle();
gui.person.tries = 6;
while(true)
{
String t = gui.getInput("Put in input\n");
System.out.println(t);
}
}
}
我的GUIHandler类
public class GUIHandler implements ActionListener
{
public static String userInput = "";
public static boolean hasinputted = false;
public JFrame frame;
public Container pane;
public PersonComponent person;
public JLabel guessedChars;
public JLabel wordDisplay;
public JTextArea text;
public JScrollPane log;
public JTextField input;
public DefaultCaret bar;
public void handle()
{
frame = new JFrame();
frame.setTitle("Hangman");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
pane = frame.getContentPane();
pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));
person = new PersonComponent();
person.tries = 0;
person.setAlignmentX(Component.CENTER_ALIGNMENT);
pane.add(person);
guessedChars = new JLabel("placeholder");
guessedChars.setFont(new Font(null, 0, 20));
guessedChars.setAlignmentX(Component.CENTER_ALIGNMENT);
pane.add(guessedChars);
wordDisplay = new JLabel("placeholder");
wordDisplay.setFont(new Font(null, 0, 20));
wordDisplay.setAlignmentX(Component.CENTER_ALIGNMENT);
pane.add(wordDisplay);
text = new JTextArea(8, 40);
text.setEditable(false);
text.setFocusable(false);
log = new JScrollPane(text);
pane.add(log);
bar = (DefaultCaret)text.getCaret();
bar.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
input = new JTextField();
input.setAlignmentX(Component.CENTER_ALIGNMENT);
input.addActionListener(this);
input.setEditable(false);
pane.add(input);
frame.pack();
frame.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent event)
{
if(!input.getText().equals(""))
{
userInput = input.getText();
input.setEditable(false);
input.setText("");
hasinputted = true;
}
}
public String getInput(String message)
{
String temp = "";
this.text.append(message);
this.input.setEditable(true);
while(true)
{
if(hasinputted)
{
temp = userInput + "\n";
userInput = "";
hasinputted = false;
break;
}
}
return temp;
}
}
首先。 当一个Java应用程序启动时, main
方法中加载的,什么是俗称,然后在“主”线程。
Swing使用它自己的线程来监视事件并执行它的功能,这被称为事件调度线程。
Swing是一个单线程环境,这意味着预期所有对UI的修改和交互都将在EDT的上下文中完成。
你的整个例子都是侥幸。 基本上在EDT上下文中运行任何类型的长时间运行任务或阻止操作(例如循环)将导致应用程序停止并停止响应用户交互和绘制请求。
通过采取一看开始在Swing并发更多的细节和特别注意一节初始线程
常见的手段来实现你仿佛是试图做的,是使用某种形式的对话的。 看看如何使对话的更多细节。 或使用观察者模式,类似ActionListener
基于评论的示例
基本上,这个例子将“等待”,直到(更正确地时通知)用户按下文本字段内回车键。 它会将值附加到文本区域......
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class HangManTest {
public static void main(String[] args) {
new HangManTest();
}
public HangManTest() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextField field;
private JTextArea area;
public TestPane() {
field = new JTextField(20);
area = new JTextArea(10, 20);
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(field, gbc);
add(new JScrollPane(area), gbc);
field.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String text = field.getText();
field.setText(null);
processGuess(text);
}
});
}
public void processGuess(String text) {
area.append(text + "\n");
}
}
}
您似乎太习惯于命令行程序来真正理解事件驱动的GUI编程。 这是一个小课。
GUI编程是事件驱动的。 这意味着GUI程序应该等待用户做某事,然后做出回应。 这对GUI编程非常重要,Java实际上为您处理事件的所有工作。 您似乎正在尝试创建某种辅助事件循环,就像您在命令行程序中看到的那样,您应该让Java执行事件处理。
看起来你要做的就是将一个刽子手应用程序与从用户那里获取输入并将其打印到控制台的内容组合在一起。 为此,只需在ActionListener
中将消息打印到控制台即可。 然后摆脱text
文本区域。 如果您认为需要在用户需要输入时附加文本“Put in input”的文本区域,则可以将文本区域的初始文本设置为“Put in input”然后将其附加到动作侦听器中。
完成上述更改后,您可以从main
删除getInput
方法和奇怪的循环。 作为最后的改变,为了更好的衡量,您可能想要了解构造函数并将代码放在构造函数中。
希望这有助于您了解事件驱动的GUI编程,并在Java中编程GUI,而不会有数千个需要大量修复的大错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.