如何使用事件调度线程?
我了解到 swing 为何不是线程安全的。深入研究后,我发现对 swing 组件的每次修改都必须在事件调度线程上完成,以防止与多线程相关的各种问题。然而,信息似乎就完全止步于此了。似乎没有一个好的教程可以解释如何在互联网上可以访问的任何地方执行此操作。
将发布的与其他问题相关的代码中的信息拼凑在一起,似乎我必须在程序中的每个挥杆修改周围放置一个凌乱的代码块(就像我自己的代码中的这个示例):
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
setTitle("Frame title");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setSize(800, 480);
setLocationRelativeTo(null);
setIconImage(Toolkit.getDefaultToolkit().createImage(ClassLoader.getSystemResource("Frame icon.png")));
}
});
} catch (Exception e) {
e.printStackTrace();
}
基本上,这是对的吗?我是否必须在代码中对 Swing 组件的每次修改都放置该代码(或与 invokeLater 等效的代码)?
另外,为什么 Swing 不自动执行此操作?
I learned about how swing isn't thread-safe. Delving deeper, I discovered that every modification to a swing component must be done on the Event Dispatch Thread in order to prevent various issues associated with multithreading. However, the information seemed to completely stop there. There doesn't seem to be a good tutorial that explains how to do this anywhere accessible on the internet.
Patching together information from code posted in relation to other issues, it seemed that I would have to put an untidy block of code around every single swing modification in my program (like this example from my own code):
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
setTitle("Frame title");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setSize(800, 480);
setLocationRelativeTo(null);
setIconImage(Toolkit.getDefaultToolkit().createImage(ClassLoader.getSystemResource("Frame icon.png")));
}
});
} catch (Exception e) {
e.printStackTrace();
}
Basically, is this right? Do I have to put that code (or the equivalent with invokeLater) around every modification to a Swing component in my code?
Also, why doesn't Swing do this automatically?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
诀窍在于,当 swing 呼叫您时,它始终会在 EDT 中,因此您不必担心。
但是,如果您处于计时器或由其他外部事件、主线程或您创建的任何其他线程触发的操作中,那么您必须使用invokeLater 或invokeAndWait。
换句话说,是的,swing 确实会自动“执行”。需要使用 invokeXx 的情况非常罕见,如果 swing 在内部执行此操作,则会浪费太多时间。
许多 Java 程序员从来没有弄清楚这一点,这可能会导致绘制 GUI 时出现一些非常令人讨厌的难以发现的问题。我确实希望 swing 在你不使用 EDT 调用它时抛出一个异常——如果使用 EDT,Java 在专业 GUI 方面会有更好的声誉,因为那里会少一些垃圾。
The trick is that when swing calls you it will ALWAYS be in the EDT, so you don't have to worry about it.
However if you are in a timer or an action triggered by some other external event, your main thread or any other thread you've created then yes, you have to use invokeLater or invokeAndWait.
In other words, yes swing does do "it" automatically. Needing to use invokeXx is so rare that if swing were to do it internally it would waste too much time.
Many java programmers never figure this out and it can cause some pretty nasty hard-to-find problems with drawing your GUI. I do wish swing threw an exception when you called it not using the EDT--Java would have a better reputation when it came to professional GUIs if it did because there would be less crap out there.
请注意,从事件处理程序执行的任何代码都已经在 EDT(缩写词中的事件)中运行,
这意味着对于一般用途(虽然您不会弄乱 swingworkers 和线程池等),您始终位于 EDT 内
,并且您可以始终使用
SwingUtilities.isEventDispatchThread()
查询是否处于 EDT还要注意,在代码中对
invokeAndWait
的调用将失败并引发错误当您已经进入 EDT 时note that any code executed from event handlers is already run in the EDT (the Event in the acronym)
this means that for general use (while you don't mess with swingworkers and threadpools and such) you are always inside the EDT
and you can always query if you are in the EDT with
SwingUtilities.isEventDispatchThread()
also note that in your code the call to
invokeAndWait
will fail and throw an error when you are in the EDT already基本上,您不会从 EDT 外部绘制或更新 GUI。
您可以从另一个线程使用 SwingUtilitis.invokeLater() 来确保 GUI 绘图或更新代码在 EDT 上运行。
Basically, you dont draw or update the GUI from outside of the EDT.
You use SwingUtilitis.invokeLater() from another thread to ensure the GUI drawing or updating code is run on the EDT.
并非所有 UI 代码都必须是 invokeLater 调用中可运行代码的一部分。这只是因为您的程序的很大一部分无论如何都会在 EDT 上运行。仅当您位于不同线程时才需要将消息分派到 EDT。
Not all your UI code must be part of a runnable in an invokeLater call. That is simply because a large part of your program will be run on the EDT anyway. You need to dispatch messages to the EDT only when you are on a different thread.