java如何正确使用Actionlistener事件的输入
我已经学习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;
}
}
# 1 楼答案
您似乎太习惯于命令行程序,无法真正理解事件驱动的GUI编程。这里有一个小教训
GUI编程是事件驱动的。这意味着GUI程序应该等待用户做一些事情,然后做一些响应。这对于GUI编程非常重要,以至于Java实际上为您完成了所有处理事件的工作。您似乎在尝试创建某种辅助事件循环,就像您在命令行程序中看到的那样,您应该让Java来处理事件
看起来你要做的是将一个hangman应用程序与一些从用户那里获取输入并打印到控制台的东西结合起来。为此,只需将消息打印到
ActionListener
中的控制台。然后去掉text
文本区域。如果您觉得需要一个文本区域,当用户需要输入时,文本“输入”被附加到该文本区域,那么您可以将文本区域的初始文本设置为“输入”,然后将其附加到动作侦听器中在进行上述更改之后,您可以从
main
中删除getInput
方法和奇怪的循环。作为最后一个更改,为了更好地衡量,您可能希望了解构造函数,并将代码放在构造函数中创建窗口希望这能帮助您理解事件驱动的GUI编程,并在java中编程GUI,而不让它们有数千个需要花费大量精力才能修复的大错误
# 2 楼答案
首先。当Java应用程序启动时,
main
方法被加载到通常称为“主”线程的线程中Swing使用自己的线程来监视事件并执行其功能,即事件调度线程
Swing是一个单线程环境,这意味着所有对UI的修改和交互都将在EDT的上下文中完成
你的整个例子都是侥幸。基本上,在EDT上下文中运行任何长时间运行的任务或块操作(如循环)都会导致应用程序暂停并停止响应用户交互和绘制请求
首先看一下Concurrency in Swing了解更多细节,并特别注意名为Initial Threads的部分
实现你似乎想做的事情的常用方法是使用某种对话。有关更多详细信息,请查看How to make dialogs。或者使用观察者模式,类似于
ActionListener
基于评论的示例
基本上,此示例将“等待”直到用户按下文本字段中的[kbd>Enter]键(更准确地说是在何时收到通知)。它会将值附加到文本区域