Why does a partially hidden JFrame not repaint properly on Linux when switching between virtual desktops
we have problems with Java 6 applications that do not properly refresh when switching virtual desktops. The problem so far has been reproduced on Fedora 11 and 13 with GNOME and Suse SLES 10 with KDE. I use the following test case to reproduce the problem:
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
public class RepaintTest {
private JLabel label;
private void createAndShowGUI() {
final JFrame frame = new JFrame("RepaintTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
label = new JLabel("Repaint Test");
label.setOpaque(true);
frame.getContentPane().add(label);
frame.pack();
frame.setSize(200, 100);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
final RepaintTest repaintTest = new RepaintTest();
repaintTest.createAndShowGUI();
new Timer(5000, new ActionListener() {
boolean flip;
@Override
public void actionPerformed(ActionEvent e) {
repaintTest.label.setBackground(flip ? Color.GREEN : Color.RED);
flip = !flip;
}
开发者_如何学Python }).start();
}
});
}
}
Start this program and move another window, for example, a terminal window, partially in front of it. Wait for the window background to become red, switch to another virtual desktop and wait for five seconds, then switch back to your original screen. The background now should be completely green. Instead, what I get is a window that is only partially updated in the visible parts not covered by the other window.
This problem does not occur with Java 5 and it does not occur when using one of the following properties at startup:
-Dswing.handleTopLevelPaint=false
or
-Dswing.bufferPerWindow=false
However, turning off Swing's double buffering seems not to be a very good option. Is this a JDK bug on Linux or can we do anything in our applications to fix this repaint problem?
Your TimerTask
needs to change the label on the event dispatch thread, e.g.
new Timer().schedule(new TimerTask() {
boolean flip;
@Override
public void run() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
repaintTest.label.setBackground(flip ? Color.GREEN : Color.RED);
flip = !flip;
}
});
}
}, 5000, 5000);
More conveniently, use javax.swing.Timer
, as its action event handler executes on the event-dispatching thread.
I tested with multiple jdks: sun 64bit 1.6.0_04 server vm, 1.6.0_21 server+client vm and openjdk 64bit 1.6.0_20 server + client vm on my ubuntu x64 10.10: all look the same, update does not work. And I also noted that it differs depending on where to cover the java window:
putting another window with the upper-left corner over the java window: only a small horizontal line is not updated
putting another window with the lower-eft corner over the java window: the rectangle left from the covering window is not updated
- putting another window with the left/right side over the java window: background is updated as expected
Update behaviour with upper/lower-right sides differ the same way.
It does not make any difference if testing on primary or secondary screen.
And I can confirm it is working
with sun 32bit jdk 1.5.0_10 server vm.
with 1.6.0_21 x86 ON WINDOWS XP using dexpot as virtual desktops manager
If the 1.5 java would not work I would have guessed it to be a XX/graphics card driver related issue. But with this working it seems related to the java vm.
精彩评论