EDT问题中的Java swing进度条

发布于 2024-09-13 19:15:57 字数 839 浏览 1 评论 0原文

这是为挥杆专家准备的。我在这个问题上花了相当多的时间,所以我需要用几行来解释这个问题。

我有一个独立的 java swing 应用程序(java 6)。在我的应用程序中,我有一个带有单选按钮组的框架。我有一个链接到组中所有按钮的操作。该操作检查哪个单选按钮被选中并执行一些工作。 “工作”涉及一些背景计算以及我的应用程序中其他两个框架中的一些绘画。后台计算是多线程的。

我想在用户选择单选按钮之一时显示进度条。 但是,当选择单选按钮时,当单选按钮的操作发生时,进度条永远不会出现。我尝试过jdialog类型的进度条、玻璃窗格等。直到“工作”全部完成后它们才会出现。这似乎是因为 Swing 在相应操作中的“工作”完成之前才完成单选按钮的绘制。由于 EDT 一次只执行一件事,因此永远不会显示进度条对话框(或玻璃窗格)。

然后我尝试使用 SwingWorker 来完成所有这些“工作”。在 SwingWorker 的 did() 方法中启动进度条(或激活玻璃窗格)、启动 SwingWorker 并关闭进度条(或停用玻璃窗格)。这似乎可以很好地调出进度条,但是作为“工作”一部分的绘画有时没有完成,给我留下了一些绘画工件(paintComponent方法非常复杂,所以不想在这里重现)。如果我调整窗口大小,这些伪影就会消失。事实上,如果我使用扩展 Thread 而不是 SwingWorker 的类,也会发生这种情况。这都是因为 Swing 不是线程安全的,并且我正在尝试从 EDT 以外的线程执行 GUI 工作。我理解那部分。

我该怎么办? “工作”大约需要 30 秒,如果不向用户显示程序正在工作的某种指示,这似乎太长了。我也尝试将光标更改为等待光标,但遇到了与上面相同的问题。我唯一能做的就是禁用框架并将框架的标题设置为一些文本,例如“正在工作...”

以前有人见过这个问题吗?

This is for the swing experts out there. I have spent considerable time on this problem, so it is going to take me a few lines to explain the problem.

I have a standalone java swing application (java 6). In my application, I have a frame with a radio button group. I have a single action linked to all the buttons in the group. The action checks to see which radio button is selected and performs some work. The "work" involves some background computation as well as some painting in two other frames in my application. The background computation is multi-threaded.

I would like to display a progress bar when the user selects one of the radio buttons.
However, when a radio button is selected, while the action to the radio button is happening, the progress bar never appears. I have tried jdialog type progress bars, glass panes, etc. None of them appear until the "work" is all completed. This seems to be because Swing does not finish painting the radio button until the "work" in the corresponding action is completed. And since the EDT only does one thing at a time, the progress bar dialog (or glass pane) is never displayed.

I then tried to use a SwingWorker to do all this "work". Start the progress bar (or activate a glass pane), start the SwingWorker and close the progress bar (or deactivate the glass pane) in the done() method for the SwingWorker. This seems to bring up the progress bar fine, but the painting which is part of the "work" is sometimes not completed, leaving me with some painting artifacts (the paintComponent method is pretty complicated, so do not want to reproduce here). The artifacts disappear if I resize the window. In fact, this happens if I use a class which extends Thread instead of SwingWorker too. This is all because Swing is not threadsafe and I am trying to do GUI work from a thread other than the EDT. I understand that part.

What do I do? "work" takes about 30 seconds and that seems too long to go without showing the user some kind of indication that the program is working. I have also tried changing the cursor to a wait cursor and have run into the same problems as above. The only thing that I can do is disable the frame and set the title of the frame to some text like "working..."

Anybody seen this problem before?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

小瓶盖 2024-09-20 19:15:57

我认为您在 SwingWorker 线程中完成工作是正确的,但您不应该尝试在那里进行绘画。

我倾向于:

  • 让 ActionListener show() 进度条,启动 swingworker 然后退出

  • 让让工作线程完成工作,并定期在进度条组件上调用 repaint()(这保证线程安全)

  • 进度条有它自己的paintComponent(将在EDT上自动调用)。如果有必要,这可以读取由工作线程更新的一些变量来测量进度

  • 当工作线程完成时,让它调用 invokeLater() 在 EDT 上运行最终关闭函数,这将隐藏进度条并执行任何其他与 GUI 相关的清理/向用户显示完成消息等。

I think you are right to do the work in the SwingWorker thread, but you shouldn't be trying to do your painting there.

I'd be inclined to:

  • Have the ActionListener show() the progress bar, set off the swingworker then exit

  • Have the worker thread do the work, and periodically call repaint() on the progress bar component (this is guaranteed to be thread safe)

  • Progress bar has it's own paintComponent (which will be automatically called on the EDT). If necessary, this can read some variable that is updated by the worker thread to measure progress

  • When the worker thread finishes, have it call invokeLater() to run a final close down function on the EDT, which will hide the progress bar and do any other GUI-related cleanup / show a completion message to the user etc.

千年*琉璃梦 2024-09-20 19:15:57

当你将工作从 EDT 转移到周转工人(这是正确的做法)时,听起来工作和绘画都转移到了周转工人。这幅画应该仍会在美国东部夏令时进行。您可以通过使用 SwingUtilities.invokeLater 从后台线程调用重绘来实现此目的,或者使用 SwingWorker.publish(V...),它将从您的工作线程获取通知并使其生效通过 SwingWorker.process(V...) 模板方法(您覆盖的)。您的process覆盖可以通过重新绘制屏幕的一部分、更新进度或根据需要采取其他适当的操作来处理中间通知。此处完成的任何 UI 更改都将可见,无需等待其余工作完成。

When you moved the work from the EDT to the swing worker (which was the right thing to do), it sounds like both the work and the painting moved to the swing worker. The painting should still happen on the EDT. You can achieve this by using SwingUtilities.invokeLater to invoke a repaint from the background thread, or by using the SwingWorker.publish(V...), which will take notifications from your worker thread and make them available on the EDT via the SwingWorker.process(V...) template method (which you override). Your process override can handle the intermediate notifications by repainting a portion of the screen, updating progress, or taking some other appropriate action as desired. Any UI changes done here will be visible without waiting for the rest of the work to complete.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文