如何阻止 JButton 执行无限循环
How to stop JButton from performing an endless loop
基本上,我要做的是在用户单击按钮时将一串文本连续附加到 JTextPane 中。只有当用户再次点击按钮时,循环才会停止。这是在我的按钮的 actionPerformed 方法中:
StyledDocument xpInfo = txtXPInfo.getStyledDocument();
if (btnGo.getText().equals("Go Adventure!")) {
btnGo.setText("Stop Adventure");
try {
do {
xpInfo.insertString(xpInfo.getLength(), "Some string\n", null);
txtXPInfo.update(txtXPInfo.getGraphics());
Thread.sleep(1000);
} while (btnGo.getText().equals("Stop Adventure"));
} catch (BadLocationException e) {
System.out.println(e);
} catch (InterruptedException ex) {
Logger.getLogger(FrmPlay.class.getName()).log(Level.SEVERE, null, ex);
}
} else if (btnGo.getText().equals("Stop Adventure")) {
btnGo.setText("Go Adventure!");
}
我写的代码好像是一个死循环。我认为这可能是因为我在按钮的 actionPerformed 方法中完成了所有这些操作,但我不知道该怎么做。如果这是一个愚蠢的问题,我很抱歉。在此先感谢所有愿意回答这个问题的人!
我认为您的问题是您阻止了 Event Thread
。在 Swing 中,OS 仅使用一个线程来分派 UI 事件(如按下按钮)。
在您的情况下,似乎您在该线程上无限循环。如果你是,那么其他按钮按下将永远不会注册,因为那个线程正忙于你的 do/while
循环。
你真正想要做的是启动一个不同的线程(有很多这样的例子)来执行追加循环,并留下 Event Thread
来调度 UI 事件。
您可以使用 ScheduledExecutorService
,因为它的主要目的是以某个指定的时间间隔在单独的线程上执行任务。但是你需要记住 所有 UI 相关的操作必须从 EDT 完成,所以你应该用 SwingUtilities.invokeLater()
包装 txtXPInfo
更新操作:
private final ScheduledExecutorService xpInfoScheduledExecutor = Executors.newSingleThreadScheduledExecutor();
private ScheduledFuture<?> xpInfoUpdatingFuture;
public void actionPerformed() {
StyledDocument xpInfo = txtXPInfo.getStyledDocument();
if (btnGo.getText().equals("Go Adventure!")) {
btnGo.setText("Stop Adventure");
xpInfoUpdatingFuture = xpInfoScheduledExecutor.scheduleAtFixedRate(
new XpInfoUpdater(), 0, 1, TimeUnit.SECONDS);
} else if (btnGo.getText().equals("Stop Adventure")) {
xpInfoUpdatingFuture.cancel(true);
btnGo.setText("Go Adventure!");
}
}
private class XpInfoUpdater implements Runnable {
@Override
public void run() {
SwingUtilities.invokeLater(() -> {
try {
xpInfo.insertString(xpInfo.getLength(), "Some string\n", null);
txtXPInfo.update(txtXPInfo.getGraphics());
} catch (BadLocationException e) {
System.out.println(e);
}
});
}
}
基本上,我要做的是在用户单击按钮时将一串文本连续附加到 JTextPane 中。只有当用户再次点击按钮时,循环才会停止。这是在我的按钮的 actionPerformed 方法中:
StyledDocument xpInfo = txtXPInfo.getStyledDocument();
if (btnGo.getText().equals("Go Adventure!")) {
btnGo.setText("Stop Adventure");
try {
do {
xpInfo.insertString(xpInfo.getLength(), "Some string\n", null);
txtXPInfo.update(txtXPInfo.getGraphics());
Thread.sleep(1000);
} while (btnGo.getText().equals("Stop Adventure"));
} catch (BadLocationException e) {
System.out.println(e);
} catch (InterruptedException ex) {
Logger.getLogger(FrmPlay.class.getName()).log(Level.SEVERE, null, ex);
}
} else if (btnGo.getText().equals("Stop Adventure")) {
btnGo.setText("Go Adventure!");
}
我写的代码好像是一个死循环。我认为这可能是因为我在按钮的 actionPerformed 方法中完成了所有这些操作,但我不知道该怎么做。如果这是一个愚蠢的问题,我很抱歉。在此先感谢所有愿意回答这个问题的人!
我认为您的问题是您阻止了 Event Thread
。在 Swing 中,OS 仅使用一个线程来分派 UI 事件(如按下按钮)。
在您的情况下,似乎您在该线程上无限循环。如果你是,那么其他按钮按下将永远不会注册,因为那个线程正忙于你的 do/while
循环。
你真正想要做的是启动一个不同的线程(有很多这样的例子)来执行追加循环,并留下 Event Thread
来调度 UI 事件。
您可以使用 ScheduledExecutorService
,因为它的主要目的是以某个指定的时间间隔在单独的线程上执行任务。但是你需要记住 所有 UI 相关的操作必须从 EDT 完成,所以你应该用 SwingUtilities.invokeLater()
包装 txtXPInfo
更新操作:
private final ScheduledExecutorService xpInfoScheduledExecutor = Executors.newSingleThreadScheduledExecutor();
private ScheduledFuture<?> xpInfoUpdatingFuture;
public void actionPerformed() {
StyledDocument xpInfo = txtXPInfo.getStyledDocument();
if (btnGo.getText().equals("Go Adventure!")) {
btnGo.setText("Stop Adventure");
xpInfoUpdatingFuture = xpInfoScheduledExecutor.scheduleAtFixedRate(
new XpInfoUpdater(), 0, 1, TimeUnit.SECONDS);
} else if (btnGo.getText().equals("Stop Adventure")) {
xpInfoUpdatingFuture.cancel(true);
btnGo.setText("Go Adventure!");
}
}
private class XpInfoUpdater implements Runnable {
@Override
public void run() {
SwingUtilities.invokeLater(() -> {
try {
xpInfo.insertString(xpInfo.getLength(), "Some string\n", null);
txtXPInfo.update(txtXPInfo.getGraphics());
} catch (BadLocationException e) {
System.out.println(e);
}
});
}
}