You've actually created an interesting demo that shows some of the important differences that occur when starting a Swing app the right and wrong ways. You've essentially summarized why the right way performed worse than the wrong way, but I've added some code to yours to enhance the demo. I also moved the runGUI() method to the TestPanel class, because that's where it really belongs. The TestWindow is the container, the TestPanel is the content, and the animation is occurring on the TestPanel, so TestPanel should contain the code that creates the animation.
There are two ways in the main() method to start the app, the right way using invokeLater() and the wrong way which calls the TestWindow() constructor on the main thread. (You can actually do both at once, but it's impossible to tell from which instance the messages are being printed, so there's little value in doing that.) I think you'll be able to verify your statement above by reviewing the messages that are printed while the app is running in the two different cases. Let me know if you have additional questions.
import java.awt.*;
import javax.swing.*;
import java.awt.geom.*;
public class TestWindow
{
private JFrame frame;
private TestPanel panel;
public TestWindow()
{
frame = new JFrame("test");
panel = new TestPanel();
frame.setContentPane(panel);
frame.setPreferredSize(new Dimension(800,600));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
System.out.println( "Swing app is started on EDT: " +
SwingUtilities.isEventDispatchThread() );
panel.runGUI();
}
public static void main(String[] args)
{
System.out.println( "Main thread is EDT: " +
SwingUtilities.isEventDispatchThread() );
// either comment out this line:
// new TestWindow();
// or comment out this entire invokeLater() call and then run.
SwingUtilities.invokeLater( new Runnable()
{
public void run()
{
new TestWindow();
}
});
}
}
class TestPanel extends JPanel
{
int x;
public TestPanel()
{
x = 0;
}
@Override
public void paintComponent(Graphics g)
{
System.out.println("checkpoint 2"); //this never comes up
System.out.println( "panel's paintComponent() method is on EDT: " +
SwingUtilities.isEventDispatchThread() );
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.draw( new Rectangle2D.Double(x,x,50,50) );
}
// note that i moved this to the TestPanel class, because that's where
// it really belongs. i would also rename it, 'animatePanel()' or similar
public void runGUI()
{
long lasttime = System.currentTimeMillis();
int waittime = 1000;
while(true)
{
long thistime = System.currentTimeMillis();
if( (thistime - lasttime) >= waittime )
{
System.out.println("checkpoint 1"); //this comes up once a second like it should when i run the program
System.out.println( "while( true ) loop is on EDT: " +
SwingUtilities.isEventDispatchThread() );
x++;
repaint();
lasttime = System.currentTimeMillis();
}
}
}
}