所以我试图设置一个应用程序,其中我在jframe中有多个面板。我们可以说其中3个纯粹用于显示目的,其中一个用于控制目的。我使用borderLayout,但我不认为布局应该真正影响这里的事情。
我的问题是:我希望三个显示面板的重新绘制在控制面板中的按钮控制之下,并且我希望每当按下控制面板上的按钮时它们都同步执行。要做到这一点,我设置了这个小方法:
public void update(){
while(ButtonIsOn){
a.repaint();
b.repaint()
c.repaint();
System.out.println("a,b, and c should have repainted");
}
}
其中a,b和c都是显示面板,我希望a,b和c连续重新粉刷,直到我再次按下按钮。问题是,当我执行循环时,消息以无限循环打印,但没有任何面板执行任何操作,即,它们都没有重新绘制。
我一直在阅读事件发送线程和摆动多线程,但到目前为止我找到的任何内容都没有真正解决我的问题。有人可以告诉我我在这里做错了什么,或者甚至更好,一些处理我所描述的情况的示例代码?感谢...
答案 0 :(得分:2)
java.util.concurrent包为并发编程提供了非常强大的工具。
在下面的代码中,我使用了ReentrantLock
(与Java synchronized
关键字非常相似,确保多个线程对单个代码块进行互斥访问)。 ReentrantLock
提供的另一件好事是Conditions
,允许Threads
在继续之前等待特定事件。
此处,RepaintManager
只是循环播放,在repaint()
上调用JPanel
。但是,当toggleRepaintMode()
被调用时,它会阻塞,等待modeChanged Condition
,直到再次调用toggleRepaintMode()
。
您应该能够立即运行以下代码。按JButton
切换重新绘制JPanel
(您可以通过System.out.println
语句查看)。
总的来说,我强烈建议您熟悉java.util.concurrent提供的功能。那里有很多非常强大的东西。在http://docs.oracle.com/javase/tutorial/essential/concurrency/
有一个很好的教程import java.awt.Component;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class RepaintTest {
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel()
{
@Override
public void paintComponent( Graphics g )
{
super.paintComponent( g );
// print something when the JPanel repaints
// so that we know things are working
System.out.println( "repainting" );
}
};
frame.add( panel );
final JButton button = new JButton("Button");
panel.add(button);
// create and start an instance of our custom
// RepaintThread, defined below
final RepaintThread thread = new RepaintThread( Collections.singletonList( panel ) );
thread.start();
// add an ActionListener to the JButton
// which turns on and off the RepaintThread
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
thread.toggleRepaintMode();
}
});
frame.setSize( 300, 300 );
frame.setVisible( true );
}
public static class RepaintThread extends Thread
{
ReentrantLock lock;
Condition modeChanged;
boolean repaintMode;
Collection<? extends Component> list;
public RepaintThread( Collection<? extends Component> list )
{
this.lock = new ReentrantLock( );
this.modeChanged = this.lock.newCondition();
this.repaintMode = false;
this.list = list;
}
@Override
public void run( )
{
while( true )
{
lock.lock();
try
{
// if repaintMode is false, wait until
// Condition.signal( ) is called
while ( !repaintMode )
try { modeChanged.await(); } catch (InterruptedException e) { }
}
finally
{
lock.unlock();
}
// call repaint on all the Components
// we're not on the event dispatch thread, but
// repaint() is safe to call from any thread
for ( Component c : list ) c.repaint();
// wait a bit
try { Thread.sleep( 50 ); } catch (InterruptedException e) { }
}
}
public void toggleRepaintMode( )
{
lock.lock();
try
{
// update the repaint mode and notify anyone
// awaiting on the Condition that repaintMode has changed
this.repaintMode = !this.repaintMode;
this.modeChanged.signalAll();
}
finally
{
lock.unlock();
}
}
}
}
答案 1 :(得分:1)
jComponent.getTopLevelAncestor().repaint();
答案 2 :(得分:0)
您可以使用SwingWorker。 SwingWorker旨在在后台执行长时间运行的任务,而不会阻塞事件调度程序线程。因此,您需要扩展SwingWorker
并实施某些对您有意义的方法。请注意,所有长时间运行的操作都应该在doInBackground()
方法中进行,而Swing UI元素只应在done()
方法上更新。
所以这是一个例子:
class JPanelTask extends SwingWorker<String, Object>{
JPanel panel = null;
Color bg = null;
public JPanelTask(JPanel panel){
this.panel = panel;
}
@Override
protected String doInBackground() throws Exception {
//loooong running computation.
return "COMPLETE";
}
@Override
protected void done() {
panel.repaint();
}
}
现在,在“控制”按钮的动作执行事件中,您可以执行以下操作:
controlButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
JPanelTask task1 = new JPanelTask(panel1);
task1.execute();
JPanelTask task2 = new JPanelTask(panel2);
task2.execute();
//so on..
}
});
另一种方法是使用javax.swing.Timer。计时器可以帮助您及时快速地对您的ui元素进行更改。这可能不是最合适的解决方案。但它也完成了工作。 再次,您应该注意在正确的位置更新UI元素。