Linux上使用模态对话框时繁忙光标的Swing渲染问题
关闭模式对话框后在应用程序框架的玻璃窗格上设置忙碌光标时,并不总是显示忙碌光标。有时它有效(第一次它通常总是有效),有时则无效。
更好的是,在打开对话框之前设置忙碌光标时。显示忙碌光标,但是当将鼠标移入对话框然后移出对话框时,忙碌光标不再显示。
请注意,我仅在 Linux 上观察到以下错误。在 Mac OS X 或 Windows 上,行为是确定性且一致的。
另一个提示,在代码示例的第一种情况下,当鼠标未进入对话框并且使用键盘选择 YES_OPTION 时,始终显示忙碌的鼠标光标。同样在这种情况下,玻璃板上的“请稍等...”标签也从未被涂上。
这里有一个 SSCCE 演示了这些错误:
import java.awt.event.*;
import javax.swing.*;
public class TestFrame extends JFrame {
private JPanel panel;
private JPanel glassPane;
public TestFrame() {
final JButton button1 = new JButton(new AbstractAction("Start activity indicator after closing the dialog") {
@Override
public void actionPerformed(ActionEvent e) {
doAction1();
}
});
final JButton button2 = new JButton(new AbstractAction("Start activity indicator before opening the dialog") {
@Override
public void actionPerformed(ActionEvent e) {
doAction2();
}
});
panel = new JPanel();
panel.add(button1);
panel.add(button2);
getContentPane().add(panel, BorderLayout.NORTH);
glassPane = (JPanel) getGlassPane();
glassPane.setLayout(new BorderLayout());
glassPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
glassPane.add(new JLabel("Please Wait..."), BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800, 600);
setVisible(true);
}
public void doAction1() {
System.out.println("IsStartingInEDT?: "+ SwingUtilities.isEventDispatchThread());
final int response = JOptionPane.showConfirmDialog(this, "Click on the YES_OPTION, busy indicator must start (if it does, try again).");
if (JOptionPane.YES_OPTION == response) {
startActivity();
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(200);
} catch (Exception e) {
e.printStackTrace();
}
}
stopActivity();
}
}
public void doAction2() {
startActivity();
System.out.println("IsStartingInEDT?: "+ SwingUtilities.isEventDispatchThread());
final int response = JOptionPane.showConfirmDialog(this, "Move the mouse inside the dialog (me) and then outside, the busy indicator is not shown anymore");
if (JOptionPane.YES_OPTION == response) {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(200);
} catch (Exception e) {
e.printStackTrace();
}
}
}
stopActivity();
}
public void startActivity() {
System.out.println("TestFrame.startActivity()");
glassPane.setVisible(true);
}
public void stopActivity() {
System.out.println("TestFrame.stopActivity()");
glassPane.setVisible(false);
}
/**
* @param args
*/
public static void main(String[] args) {
new TestFrame();
}
}
目前我在 JavaBug 队列中没有发现任何相关问题。在打开新的之前我会进一步搜索。
我也已经阅读了以下文章,但它不是很方便,因为从非模态对话框制作一个好的模态对话框并不简单: http://www.javaspecialists.eu/archive/Issue065.html
任何人都可以提供一些帮助? 预先感谢,皮埃尔
When setting a busy cursor on the glass pane of the application frame after closing a modal dialog, the busy cursor is not always displayed. Sometimes it works (the first time it is mostly always working), sometimes not.
Even better, when setting the busy cursor before opening the dialog. The busy cursor get displayed but when moving the mouse inside and then outside the dialog the busy cursor is not displayed anymore.
Note that I observe the following bug on Linux only. On Mac OS X or Windows the behavior is deterministic and consistent.
Another hint, in the first case of the code sample, when the mouse is NOT entering the dialog and the YES_OPTION is selected using the keyboard, the busy mouse cursor is always shown. Also in this case, the "Please wait..." label on the glass pane get never painted.
Here a SSCCE demonstrating these bugs:
import java.awt.event.*;
import javax.swing.*;
public class TestFrame extends JFrame {
private JPanel panel;
private JPanel glassPane;
public TestFrame() {
final JButton button1 = new JButton(new AbstractAction("Start activity indicator after closing the dialog") {
@Override
public void actionPerformed(ActionEvent e) {
doAction1();
}
});
final JButton button2 = new JButton(new AbstractAction("Start activity indicator before opening the dialog") {
@Override
public void actionPerformed(ActionEvent e) {
doAction2();
}
});
panel = new JPanel();
panel.add(button1);
panel.add(button2);
getContentPane().add(panel, BorderLayout.NORTH);
glassPane = (JPanel) getGlassPane();
glassPane.setLayout(new BorderLayout());
glassPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
glassPane.add(new JLabel("Please Wait..."), BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800, 600);
setVisible(true);
}
public void doAction1() {
System.out.println("IsStartingInEDT?: "+ SwingUtilities.isEventDispatchThread());
final int response = JOptionPane.showConfirmDialog(this, "Click on the YES_OPTION, busy indicator must start (if it does, try again).");
if (JOptionPane.YES_OPTION == response) {
startActivity();
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(200);
} catch (Exception e) {
e.printStackTrace();
}
}
stopActivity();
}
}
public void doAction2() {
startActivity();
System.out.println("IsStartingInEDT?: "+ SwingUtilities.isEventDispatchThread());
final int response = JOptionPane.showConfirmDialog(this, "Move the mouse inside the dialog (me) and then outside, the busy indicator is not shown anymore");
if (JOptionPane.YES_OPTION == response) {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(200);
} catch (Exception e) {
e.printStackTrace();
}
}
}
stopActivity();
}
public void startActivity() {
System.out.println("TestFrame.startActivity()");
glassPane.setVisible(true);
}
public void stopActivity() {
System.out.println("TestFrame.stopActivity()");
glassPane.setVisible(false);
}
/**
* @param args
*/
public static void main(String[] args) {
new TestFrame();
}
}
At the moment I did not find any related issues in the JavaBug parade. I will search further before opening a new one.
I also already read the following article but it is not very convenient as making a good modal dialog from a non-modal one is not straightforward:
http://www.javaspecialists.eu/archive/Issue065.html
Can anyone provide some help?
Thanks in advance, Pierre
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您在这里遇到一些线程问题。
IsStartingInEDT 是真的吗?
如果是,那么您做错了,因为:
如果不是,那么您就做错了,因为:
你应该这样做:
You have some threading issue here.
Is
IsStartingInEDT
true?If yes, you are doing it wrong because:
If no, you are doing it wrong because:
OptionPane.showConfirmDialog()
must be called from the UI thread.you should do something like this:
第一。通过使用
Tread.sleep(int)
肯定会阻止 EDT,所有问题都与 Swing 中的并发2.nd 之所以有效,是因为 JOptionPane 的初始化创建了一个新的 EDT,
这里是关于 .... 的简单演示,请仅举个例子,并确保这是违反所有 Swing 规则,但通过在 EDT 期间使用 Tread.sleep(int) 演示了锁定和解锁 EDT
< img src="https://i.sstatic.net/Xubhb.png" alt="在此处输入图像描述">
结论 ->您可以创建新的
Thread
作为包装到Runnable
中的BackGroung任务,如果您想模拟LongRunning任务并使用Thread.sleep(int),也许可以回答您的问题位于此处确保正确的方法是使用 SwingWorker , Thread.sleep(int) 也是如此
1st. by using
Tread.sleep(int)
pretty sure to block EDT, with all issues desribed about Concurrency in Swing2.nd works because initializations for JOptionPane create a new EDT
here is simple demonstrations about ...., please that only example and be sure that is against all Swing rules, but demostrated lock and unlock EDT by usage Tread.sleep(int) during EDT
conclusion -> you can create new
Thread
as BackGroung Task(s) wrapped intoRunnable
, if you wnat to simulate LongRunning Task and with Thread.sleep(int), maybe answer to your question is heresure correct way would be by using SwingWorker for that, with Thread.sleep(int) too