简体   繁体   English

从EDT问题Java摇摆进度条

[英]Java swing progress bar from EDT problem

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). 我有一个独立的java swing应用程序(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. 我尝试了jdialog类型的进度条,玻璃窗格等。在“工作”全部完成之前,它们都没有出现。 This seems to be because Swing does not finish painting the radio button until the "work" in the corresponding action is completed. 这似乎是因为Swing没有完成对单选按钮的绘制,直到相应动作中的“工作”完成。 And since the EDT only does one thing at a time, the progress bar dialog (or glass pane) is never displayed. 由于EDT一次只做一件事,因此从不显示进度条对话框(或玻璃窗格)。

I then tried to use a SwingWorker to do all this "work". 然后我尝试使用SwingWorker来完成所有这些“工作”。 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. 启动进度条(或激活玻璃窗格),启动SwingWorker并关闭SwingWorker的done()方法中的进度条(或停用玻璃窗格)。 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). 这似乎提升了进度条很好,但是作为“工作”一部分的绘画有时候没有完成,留下了一些绘画工件(paintComponent方法非常复杂,所以不想在这里重现)。 The artifacts disappear if I resize the window. 如果我调整窗口大小,工件就会消失。 In fact, this happens if I use a class which extends Thread instead of SwingWorker too. 事实上,如果我使用扩展Thread而不是SwingWorker的类,就会发生这种情况。 This is all because Swing is not threadsafe and I am trying to do GUI work from a thread other than the EDT. 这都是因为Swing不是线程安全的,我试图从除EDT之外的线程进行GUI工作。 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. “工作”大约需要30秒,如果没有向用户显示程序正在运行的某种迹象,那么这似乎太长了。 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..." 我唯一能做的就是禁用框架并将框架的标题设置为“work ......”等文本。

Anybody seen this problem before? 以前有人见过这个问题吗?

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. 当你将作品从EDT移动到摇摆工作者(这是正确的事情)时,听起来工作和绘画都转移到摇摆工作者身上。 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). 您可以通过使用SwingUtilities.invokeLater从后台线程调用重绘,或者使用SwingWorker.publish(V ...)来实现此目的,它将从您的工作线程获取通知,并通过SwingWorker在EDT上使用它们.process(V ...)模板方法(您覆盖)。 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. 您的process覆盖可以通过重新绘制屏幕的一部分,更新进度或根据需要采取其他适当的操作来处理中间通知。 Any UI changes done here will be visible without waiting for the rest of the work to complete. 在此处完成的任何UI更改都将可见,而无需等待其余工作完成。

I think you are right to do the work in the SwingWorker thread, but you shouldn't be trying to do your painting there. 我认为你在SwingWorker线程中完成这项工作是正确的,但你不应该试图在那里做你的绘画。

I'd be inclined to: 我倾向于:

  • Have the ActionListener show() the progress bar, set off the swingworker then exit 让ActionListener show()进度条,设置swingworker然后退出

  • Have the worker thread do the work, and periodically call repaint() on the progress bar component (this is guaranteed to be thread safe) 让工作线程完成工作,并定期调用进度条组件上的repaint()(这保证是线程安全的)

  • Progress bar has it's own paintComponent (which will be automatically called on the EDT). 进度条有自己的paintComponent(将在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. 当工作线程完成时,让它调用invokeLater()以在EDT上运行最终关闭功能,这将隐藏进度条并执行任何其他与GUI相关的清理/向用户显示完成消息等。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM