Skip to main content

Problems with Painting Window Twice

5 replies [Last post]
avromf
Offline
Joined: 2003-06-12
Points: 0

Hi,

I am trying to debug a mature (read:has been around for a while) Swing application which has the following problem:

Whenever the application opens a new window (JFrame), if it is going to open it maximized, it will do a pack, set to maximized state, and a setVisible(true).
However, when displayed on screen, I notice it first paints the contents of the window at the "packed size" then a split second later paints it maximized. This is more noticable on slower machines as well.

To help debug the problem, I created a sample window (JFrame) that contains a JTable and three buttons (i.e. no "legacy code").
I do the following:
pack();
int state = getExtendedState();
state |= Frame.MAXIMIZED_BOTH;
setExtendedState(state);
setVisible(true);

And the same problem occurs.

I also tried to show the window early on in the startup sequence of the application and there is no issue. The issue only occurs towards the end of the startup sequence but I cannot pinpoint the exact time (my guess is something's occurring on another thread?).

I also overrode the paint() method on the test JFrame and put a breakpoint there.
Early on when it paints correctly, the paint method is called once. Afterwards, it is always called twice.
When I was testing it today both paint method calls were the result of an InvocationEvent.
Each InvocationEvent has a Runnable an in this case they were SystemEventQueueUtilities.ComponentWorkRequest objects. I noticed that in one of the paint calls, the object had the same id (i.e. it was the same object).

So, my question is the following:
What could be causing this?
And what are some strategies in uncovering the cause of this?

For the record, I am testing this under Windows XP, Java 1.6 Update 11. It has had this issue for all versions of 1.6. I'm using the Windows look and feel and I also tested it under the Nimbus look and feel. Same issue.

In addition, if a window is not displayed initally in its maximized state but in its "packed size", I notice it first paints the window border and then paints the contents. I feel it is the same issue.
In addition, previous versions of Java had this issue but the background within the window border was opaque before it painted the contents. It had this issue in 1.5, 1.4, and, if I can even remember correctly, 1.3.

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
avromf
Offline
Joined: 2003-06-12
Points: 0

I was able to duplicate this isse independantly of the application.

[code]
public class TestList
{

static public class TestFrame extends JFrame
{
public TestFrame()
{
super("Test Table");
getContentPane().setLayout(new BorderLayout());
JTable table = new JTable(getRowData(), getColumnNames());
JScrollPane scrollPane = new JScrollPane(table);
getContentPane().add(scrollPane, BorderLayout.CENTER);
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
for (int i = 1; i <= 3 ; i++)
{
JButton button = new JButton("Button " + i);
buttonPanel.add(button);
}
getContentPane().add(buttonPanel, BorderLayout.SOUTH);
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
// Runnable runnable = new Runnable()
// {
// public void run()
// {
pack();
int state = getExtendedState();
state |= Frame.MAXIMIZED_BOTH;
setExtendedState(state);
setVisible(true);
// }
// };
// Thread thread = new Thread(runnable);
// thread.start();

// System.out.println("Double Buffered: " + getRootPane().isDoubleBuffered());
// Frame[] frames= Frame.getFrames();
// for (int i = 0; i < frames.length; i++)
// {
// System.out.println(frames[i].getClass().getName() + " Title: " + frames[i].getTitle());
// }
}

private Object[] getColumnNames()
{
return new String[]
{"First Name", "Last Name"};
}

private Object[][] getRowData()
{
String[][] rowData = new String[100][2];
for (int i = 0; i < 100; i++)
{
rowData[i][0] = "John";
rowData[i][1] = "Smith";
}
return rowData;
}
@Override
public void paint(Graphics g)
{
System.out.println("Bounds: " + g.getClipBounds());
super.paint(g);
}
}

public TestList()
{
// Runnable runnable = new Runnable()
// {
// public void run()
// {
TestFrame testFrame = new TestFrame();
// }
// };
// Thread thread = new Thread(runnable);
// thread.start();
}
public static void main(String[] args)
{
try
{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (Exception e)
{
e.printStackTrace();
}

SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
TestList testList = new TestList();
}
});
}
}
[/code]

In this case, I get the issue in which it paints twice.

However, if I remove the SwingUtilities.invokeLater and instantiate TestList, I do not get the issue.

kirillcool
Offline
Joined: 2004-11-17
Points: 0

Don't call pack()?

avromf
Offline
Joined: 2003-06-12
Points: 0

No, that will not work because although that will result it the window being maximized and paint being called once, if a user clicks on restore down it will restore down to a minimum size.
You want a user to have a "normally sized" window if they do this.

In addition, it still has the basic issue, namely that if I show the window early on (or run indenpendant of the given app) it will always call paint once and display correctly on screen. My understanding is that paint would only be called on visible components thus calling pack() then setting the extended state to maximized before calling setVisible(true) will result in a single paint call.

I'm trying to basically identify what legacy code (read: code that some other developer stuck in a long time ago) in our app is triggering this issue so I can fix it.

kirillcool
Offline
Joined: 2004-11-17
Points: 0

Call setPreferredSize(getPreferredSize()) - would that help?

avromf
Offline
Joined: 2003-06-12
Points: 0

No it does not.

And I'm not really looking for a workaround to treat the symptom but rather what the cause is.