我有一个使用 addShutdownHook() 处理 Ctrl+C 的 Swing 应用程序,它工作正常,直到我有一个关闭任务调用一个函数,该函数在正常情况下更改 JLabel 文本,此时它挂起。
我认为问题在于 Swing EDT 已终止或正在等待某些事情。
有没有办法确定 EDT 已终止或“完成”(因此我可以避免调用 Swing 方法),或者防止在 Ctrl-C 上通常关闭所有窗口的行为?
只是为了澄清:
我在一个名为 的类中有一个方法stop()。在正常情况下,这可以被调用(连同它的补码start()),它会触发一连串的事情,导致 JLabel 被更新,以获得stop()已经发生的视觉反馈。
当我的关闭挂钩运行时,我需要调用stop()以正常关闭某些资源。
我要问的是如何检测 Swing EDT 不存在,以便我可以重写,stop()以便检测缺少 Swing 并避免调用 Swing 函数。
我有一个越来越慢的 GUI 应用程序。我想开始为各种 GUI 任务引入计时——但是,我们的许多 GUI 操作会触发其他操作,然后“稍后调用”以触发其他操作。
最终,一切都安定下来,没有什么可做的了。此时,我想停止计时器并报告 GUI“动作”花费了多长时间。
我认为这样做的方法是实现一个名为invokeOnceIdle(Runnable task). 只有当 AWTEventQueue 为“空”时,该方法才会执行提供的任务。即提供的“任务”应该是队列中的最后一件事。
这样做的一种方法是,是否有一种方法可以指定“最低”优先级SwingUtilities.invokeLater- 但这是不可能的。
我接下来查看是否可以“invokeLater”一个 Runnable 来检查事件队列是否为“空”——但是没有公共方法可以查看事件队列是否真的为空。
做到这一点的最佳方法是什么?
假设我拥有的方法有时在Event Dispatch Thread上调用,有时则不然.现在假设我希望在该方法中的一些代码调用除事件调度线程之外的线程.
有没有办法在此时在EDT以外的线程上运行某些代码?
我试过这个:
if (SwingUtilities.isEventDispatchThread()) {
new Runnable() {
@Override
public void run() {
myMethod();
}
}.run();
} else {
myMethod();
}
Run Code Online (Sandbox Code Playgroud)
但是即使我创建了一个新的Runnable,myMethod()也最终在EDT上运行.
有没有办法在此时在EDT以外的线程上运行myMethod()?
我有一个使用a的GUI JProgressBar.GUI具有JBUTTONs以下代码:
public void updateProgressBar(int x) {
System.out.println(javax.swing.SwingUtilities.isEventDispatchThread());
healthBar.setValue(x);
}
Run Code Online (Sandbox Code Playgroud)
但我也做了一个循环,定期调用相同的方法.
public class Loop implements Runnable {
public void run() {
while (true) { Thread.sleep(2000); updateProgressBar(0); }
}
}
Run Code Online (Sandbox Code Playgroud)
现在,据我所知,任何改变我的GUI都需要从EDT执行.JProgressBar.setValue(x)更改我的GUI,当从Loop类调用它时,isEventDispatchThread检查失败,这是好的和明白的.然而,我无法理解的是,如果这也意味着我应该使用SwingUtilities.invokeLater()on setValue().我担心的是,因为我不知道setValue()实际上是如何工作的,所以我invokeLater()不必要地使用它,甚至在使用它时破坏了一些东西.
我不知道如何更好地问我的问题:如果我知道改变我的GUI的方法没有从EDT调用,那么我是否也知道我必须使用invokeLater()?
我打印简单的值来JTextArea使用简单的for循环追加,当我运行它时,如果我在控制台输出中打印值,它就正常运行...
但是如果我JTextArea在文本区域中追加并打印值,则在整个程序运行后将它们全部附加.
public class SwingThread {
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
SwingThread window = new SwingThread();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public SwingThread() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, …Run Code Online (Sandbox Code Playgroud) 所以如果 Event Dispatch Thread 是一个独立于主线程的线程,那让我觉得下一个代码会输出
Before
Runnable
true
After
Run Code Online (Sandbox Code Playgroud)
但是当我运行它时,就好像 EDT 在运行invokeLater(..)方法内的代码块之前等待主线程完成。输出是:
Before
After
Runnable
true
Run Code Online (Sandbox Code Playgroud)
编码:
Before
Runnable
true
After
Run Code Online (Sandbox Code Playgroud)
但是,如果我替换invokeLater(..)为invokeAndWait(..),那么我得到
Before
Runnable
true
After
Run Code Online (Sandbox Code Playgroud)
这让我觉得 EDT 并不是一个真正的独立线程,或者至少在这个例子中它的行为或只是在我看来不是。你怎么解释这个?
我是Swing的新手,目前正在尝试在NetBeans中开发一个简单的GUI应用程序.
我想创建某种GUI日志记录系统,将应用程序正在执行的当前操作写入TextArea.
举个简单的例子,我创建了一个只包含2个对象的JFrame表单:一个"开始"按钮和一个TextArea.
当按下"开始"按钮时,它会调用某种冗长的方法,该方法需要一些时间(比方说,10秒)才能完成运行,并且在此方法运行时,我想将文本追加到TextArea中冗长的方法(当然我希望TextArea能够立即更新).
我的问题是我无法找到正确的方法.无论如何我尝试这样做,当我按下"开始"按钮时,应用程序冻结了10秒钟,没有像我想要的那样更新TextArea.只有在方法完成后,我才会看到TextArea的更新.
这是一个示例代码:
private void startButtonActionPerformed(java.awt.event.ActionEvent evt) {
try {
for (int i = 0; i < 10; i++) {
textArea.setText(i + "\n");
Thread.sleep(1000);
}
} catch (Exception e) {}
}
Run Code Online (Sandbox Code Playgroud)
在这个例子中,我希望看到的是,一旦我单击按钮,在接下来的10秒内,每隔一秒就会在TextArea上附加一行,如下所示:
1
2
3
4
...
但是我从这段代码得到的真实结果是应用程序冻结了10秒钟,最后TextArea被更新并仅显示数字9.
我已经尝试了许多不同的方法,主要使用SwingUtilities.invokeLater和SwingWorker方法,但它们都不适合我.
任何帮助找到正确的方法,将不胜感激.
java user-interface swing multithreading event-dispatch-thread
JDialog dialog = new JDialog(parent JFrame, "blabla");
dialog.setLayout(new BorderLayout());
JLabel label = new JLabel("more blabla");
dialog.getContentPane().add(label, BorderLayout.CENTER);
dialog.setSize(new Dimension(280, 80));
dialog.setLocationRelativeTo(parent JFrame);
dialog.setVisible(true);
//part of code that takes time to execute
//actually, I'm sending an email here, but it doesn't really matter what I do,
//as you will read below
dialog.dispose();
Run Code Online (Sandbox Code Playgroud)
我有上面的代码,它的用途是在执行某些代码时向用户显示消息(代码执行大约需要5-10秒,我不希望用户认为程序冻结).
问题是,添加到对话框中的JLabel根本没有出现.无论我添加到对话框中,它都不会出现.
但是,如果我将JDialog设置为modal(将true添加为上述构造函数的最后一个参数),它会出现,但是我想要执行的代码在对话框关闭之前不会运行,从而违背了它的目的.
由于它在代码中的位置,将要执行的代码并不重要,我尝试将其保留在当前的上面 - 根本没有执行代码 - 对话框会显示为瞬间,但我可以看到它空了.
我知道我可以创建一个构造窗口并说"待机10秒,代码正在执行",但我不想这样做.
我也尝试将JDialog换成JFrame,文本仍然不会出现.
我错过了什么?
我正在尝试创建一个客户端/服务器应用程序.问题是客户端的确认按钮第一次输入工作,但如果我为另一个输入点击相同的按钮,客户端GUI将冻结.
为什么GUI会冻结?
客户:
public class ClientGui
{
private JFrame frmBookPointOf;
private JTextField txtRm;
private JTextArea txtrBookDetails;
private JTextField textField;
private JTextField textField_1;
private JTextField textField_2;
private JTextField textField_3;
private JTextField textField_4;
private JTextField textField_5;
private JComboBox comboBox_1;
private JComboBox comboBox;
private dbController dbCtrl;
private Connection conn;
private static Socket client;
private static BufferedReader fromServer = null;
private static DataOutputStream toServer = null;
/**
* Launch the application.
*/
public static void main(String[] args) {
try {
client = new Socket("127.0.0.1", …Run Code Online (Sandbox Code Playgroud) 我开发汽车管理系统的程序.然后,当汽车进来和开车时,我想发送邮件给这家公司的老板.我的代码可以成功发送邮件,但我注意到,当邮件发送完成时,其他JFrame窗口会冻结(我无法在所有JFrame窗口上执行任何操作).这通常适用于Javamail还是有办法使其他JFrame仍然有效?
在我的程序中,完成发送一封邮件大约需要10秒钟.
java ×10
swing ×9
awt ×1
concurrency ×1
invokelater ×1
jakarta-mail ×1
jbutton ×1
jdialog ×1
jframe ×1
jprogressbar ×1