I'm a little confused about the Swing painting model.
Suppose that I have a JComponent comp, and I do something like:
c.setBackground(Color.RED);
c.setBackground(Color.YELLOW);
Obviously, the end result is that the color is yellow.
How does Swing handle this?
Does the first call trigger an immediate repaint so there'll be a short flicker of red before the yellow? Is this sequence significantly slower than just a paint of yellow?
If I was running this from outside the Swing Event thread, I would assume that in most cases (though a race condition is possible), by the time the Swing EDT comes visiting the property is already set to yellow so there'll never be any red painted.
However, my understanding is that I should make these calls from inside a Runnable in the Swing EDT. Is that correct? In that case it would seem like the EDT would have to fully perform each change without any "lookahead"?
The area of the window is marked dirty immediately. A paint request will later come back on the EDT. The OS or the event queue mechanism (or even the component) may merge repaint events (strictly a quality of implementation matter, but in practice repaints in the same window will be merged, even if they do not intersect).
Methods on Swing components should be called on the EDT. The Event Dispatch Thread belongs to AWT, not Swing.
First of all you should not make such calls outside of EDT. The results can be unpredictable.
Since all Swing components are double-buffered you will see no flicker when doing this. In addition to that all consecutive repaint requests are joined into one when possible.
Overall, you shouldn't see any issues at all when doing this as long as it is done on EDT
Related
We have following methods:
java.awt.Component#repaint()
This is old method that repaints in AWT. It does not repaint immediately, it schedules repaint.
javax.swing.JComponent#repaint(long, int, int, int, int)
This is new swing method that repaints in Swing. It schedules repaint with the RepaintManager.
Both of them may be invoked from a user thread as well as from the event-dispatching-thread.
Which of them is the most correct way to repaint Swing component (JComponent)?
Which of them is the most correct way to repaint Swing component (JComponent)?
Both of them are the correct way.
Swing components always invoke repaint() when you change a property of the component by using setText(), setForeground(), setBackground() etc. This will make sure the entire component is repainted.
The repaint(...) method can be invoked if you need to optimize painting of the component. If you have a large component and only a small part of the component changes you can use this method. However, I would recommend you don't worry about this. Swing painting is double buffered and efficient so there is rarely a case when you need to optimize the painting code.
Is the setBounds() method of a Component like JPanel called on the Event Dispatch Thread? I am asking this because I am writing a program that draws platforms and uses a Swing Timer to move them up. I override the setBounds() method so that every time the JPanel is resized, the platforms will resize too. I just want to make sure that setBounds() doesn't resize the platforms while the Timer is moving them. Also, would it be better to use a WindowListener to check if the JPanel was resized?
setBounds() will be called on the EDT by Swing code, but you have to ensure your code's own invocations of setBounds() also only calls it on the EDT. If you can ensure all calls of setBounds() occur on the EDT, then you shouldn't have to worry about setBounds() being executed while your SwingTimer is being executed because SwingTimers also execute on the EDT by default (so they won't execute at the same time).
Also I never seen someone override setBounds() so I do wonder if there's not an alternative solution such as just querying the bounds every time your SwingTimer executes. Using a listener listening for window resizes like you say does sound much better.
just working on some code to do with java graphics, very simple example from a lecture I had today. Anyway, the internet seems to say that update will not be called by a System trigger such as resizing a frame etc. In this example, update is called by such a trigger (hence update and paint are called when I only expect paint to be called). He seemed to put it down to Operating Systems and different results on each.
Can anyone clarify this for me?
Working on windows 7
Thanks in advance
Ben
Here's a great article that really says it all:
http://java.sun.com/products/jfc/tsc/articles/painting/
1) Painting in AWT
To understand how AWT's painting API works, helps to know what
triggers a paint operation in a windowing environment. In AWT, there
are two kinds of painting operations: system-triggered painting, and
application-triggered painting.
2) System-triggered Painting
In a system-triggered painting operation, the system requests a
component to render its contents, usually for one of the following
reasons:
The component is first made visible on the screen.
The component is resized.
The component has damage that needs to be repaired. (For example, something that previously obscured the component has moved, and a
previously obscured portion of the component has become exposed).
3) App-triggered Painting
In an application-triggered painting operation, the component decides
it needs to update its contents because its internal state has
changed. (For example,. a button detects that a mouse button has been
pressed and determines that it needs to paint a "depressed" button
visual).
4) The Paint Method
Regardless of how a paint request is triggered, the AWT uses a
"callback" mechanism for painting, and this mechanism is the same for
both heavyweight and lightweight components. This means that a program
should place the component's rendering code inside a particular
overridden method, and the toolkit will invoke this method when it's
time to paint.
I've customized a JPanel that displays a large, complicated diagram. Depending on the size of the data, it can take a few minutes to render in paintComponent(). I'm looking for a strategy to:
draw the component without tying up the event dispatch thread.
draw something in the JPanel to let the user know the image is being rendered.
periodically update another container's label to show the progress
I've researched this a bit, and I'm wondering if the right strategy is to use a SwingWorker to create a background thread and draw to a BufferedImage. Timers would handle the status updates. Class member variables would hold the status.
Am I on the right track?
You need to look into using a SwingWorker. You should do the rendering of the diagram in a separate thread. The SwingWorker will help accomplish that.
To get started with multi-threading in concurrency, sun has a great tutorial that should prove very helpful.
Use background image which is updated by special working thread. Then in JPanel's paintComponent() method just paint this image. The strategy is called double-buffering. You have background and foreground image. If separate thread finish the painting of data then set this image as foreground and foreground load as background. Invalidate JPanel and continue painting on back image if necessary.
I have a little java applet where I create 2 threads, one thread repaints and the other moves an image from a point to where the user clicks. The problem is that when I call the move function it loops until the image is where the user clicks but it wont repaint until I break out of the loop even though the thread doing the moving and the thread doing the painting are separate.
shortened version of key points:
my program is an applet using the paint() method
I have 2 threads one moves an image and the other paints that image
when I am moving the image it is in a while loop
the painting thread is still calling repaint() but that is as far as the call goes, it never repaints
thank you for your time.
It might be useful to read an introduction of the painting system of the AWT framework of Java. Take a look for example at th one from Sun: http://java.sun.com/products/jfc/tsc/articles/painting/index.html
In your case you don't need 2 threads. The thread in charge of repainting your applet is created by AWT. It is called the event dispatching thread or EDT. So you just need to change the position of your image and on each change call the repaint method on your applet.