[英]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.