And here's a really dumb program that follows the bullet points at the bottom of that link to perform active rendering in Swing, off the EDT:
Graphics g = myPanel.getGraphics();
g.fillRect(0, 0, myPanel.getWidth(), myPanel.getHeight());
g.drawRect((int)ballX, (int)ballY, 100, 100);
I don't think that you understand the problem, which is to paint Swing components inside the game loop, not rendering inside an empty JPanel. There should be a swingComponent.paint(g) in there.
When you switch to active rendering you're in control of paint() not the EDT.
setIgnoreRepaint only stops the operating system (OS) events from calling paint, not internal changes to the menu. See the java docs:
Sets whether or not paint messages received from the operating system should be ignored. This does not affect paint events generated in software by the AWT, unless they are an immediate response to an OS-level paint message.
This is useful, for example, if running under full-screen mode and better performance is desired, or if page-flipping is used as the buffer strategy.
So for example, if the game logic calls setText(String) on an in-game GUI JLabel, then inside the JLabel.setText method repaint is called, which posts an even to the EventQueue, which will occur on the EDT even though setText was called from the game loop thread, conflicting with the painting of that button in my game loop thread.
Stopping this is difficult, as basil said it requires 'interception' of the event on the EDT which is not easy. I thought it was impossible since no-one has shown how it is done without reflection hacks, but I'm open to being proved wrong. nsigma is the only person who has offered reasonable advice, and even then I wonder if it's possible.
You can do all that already! To paint, you could use active rendering, or if you're running your game loop in the EDT you could control the default Swing paint mechanism. For the other two, use Toolkit.getSystemEventQueue() to get access to the queue. If you're running your game loop in the EDT, just pull events and dispatch (see component.dispatchEvent()). Otherwise, push your own EventQueue implementation on top of the existing and override EventQueue.dispatchEvent() to filter / pass to your game thread. The latter might have an issue if anything was using EventQueue.isDispatchThread() though.
nsigma at least understands the problem and offers some directions to the solution. The run-your-game-loop-on-the-EDT solution is obvious and isn't the solution I'm after which is painting the GUI in my own thread.
How do you push your own EventQueue? I note that there is Toolkit.getEventQueue but no Toolkit.setEventQueue()?
I would like to see your EDT-event interception idea work. As I said, no-one has demonstrated this being done that I have ever found.
Nuff of this. We all have our ill-informed moments. No need to 'gang up' on our beloved Keith. I'm sure lots of people found new information in this thread about the inner workings of Swing - we should focus on sharing such information instead of telling eachother how ill-informed we are, over and over and over. We don't need N similar corrections from N people quoting the same statement. It gets old rather quickly.
Thanks, it's nice to be beloved! I'll be the first person to admit that I'm wrong, but so far it seems that people either don't understand the problem or dismiss it as not being a problem.
I would like to treat the GUI like everything else in a game: with an update and a paint method. I thought that is what we would all want
Like I've said several times now, this is not just a Swing thing. Almost every GUI library (including OpenGL, Android, JavaFX, libGDX, and JMonkeyEngine) uses this model. I promise that the people behind these libraries have put more thought into it than you or I.
If every GUI library has an EDT like Swing, I'm surprised. I think it's a design deficiency because it's inflexible. According to the principal of loose-coupling, Swing's event system, painting and logic should be separable, but clearly they aren't.
Edit: And like Cas says, none of this really matters. If you really think you need to go through all of this rigmarole with active rendering and threading in Swing: you're either wrong, or you should be using a different library that handles it for you.
On the whole I like the swing libary and it's what I know. If I could re-use it in my games I would. But the way it enforces everything to be done on the EDT is quite irritating. I will try libgdx's scene2d.ui, nifty or TWL for my next projects.
That tutorial guide gives no working examples, and even worse, it seems to indicate that active-rendering swing components from a non-EDT game loop thread in a thread safe way is impossible, since it says:
Don't put drawing code in the paint routine. You may never know when that routine may get called! Instead, use another method name, such as render(Graphics g), which can be called from the paint method when operating in windowed mode, or alternately called with its own graphics from the rendering loop.
It seems to indicate that a swing component's paint method can be called at any time from the EDT (with or without setIgnoreRepaint) and therefore you can't truly paint swing components in your own game loop thread.
By the way, it's great to be part of a forum where we can debate interesting topics like this.