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.
Related
I've seen it written on this site a number of times (such as here, and here) that you mustn't call setVisible(true) before adding components to a JComponent, but I haven't seen an explanation, and information on the internet seems scarce.
Why is this the case, and what happens if you break the rule?
You're not breaking anything if you call it first, but you will probably then need to call it again if you've added anything. Else Swing won't render the added components. You need to have the JVM call the JFrame's paint(...) method to have the JFrame's components rendered, and setVisible(true) will ask the JVM to do just this. If you've ever add components after calling setVisible(true) and don't see the components, you'll find that they'll "materialize" if you re-size the JFrame. This is because re-sizing it causes the operating system to ask Swing to repaint the GUI, and this will result in paint(...) being called.
Note that if you add a component after creating your GUI, you can call revalidate() and often repaint() on its container to get the new component laid out correctly and then rendered. The repaint() will definitely be necessary if the change in components involves a deletion, or a component being drawn where another component was visualized previously.
A book suggestion that I highly recommend: Filthy Rich Clients buy Guy and Haase. Just buy it! You won't regret the purchase.
Amplifying on #Hovercraft's helpful analysis, you may also have to re-pack() the enclosing top-level container. This example, which adds elements to a JList after setVisible(), may illustrate the trade-offs.
I've seen it written on this site a number of times (such as here, and here) that you mustn't call setVisible(true) before adding components to a JComponent, but I haven't seen an explanation, and information on the internet seems scarce.
Why is this the case, and what happens if you break the rule?
You're not breaking anything if you call it first, but you will probably then need to call it again if you've added anything. Else Swing won't render the added components. You need to have the JVM call the JFrame's paint(...) method to have the JFrame's components rendered, and setVisible(true) will ask the JVM to do just this. If you've ever add components after calling setVisible(true) and don't see the components, you'll find that they'll "materialize" if you re-size the JFrame. This is because re-sizing it causes the operating system to ask Swing to repaint the GUI, and this will result in paint(...) being called.
Note that if you add a component after creating your GUI, you can call revalidate() and often repaint() on its container to get the new component laid out correctly and then rendered. The repaint() will definitely be necessary if the change in components involves a deletion, or a component being drawn where another component was visualized previously.
A book suggestion that I highly recommend: Filthy Rich Clients buy Guy and Haase. Just buy it! You won't regret the purchase.
Amplifying on #Hovercraft's helpful analysis, you may also have to re-pack() the enclosing top-level container. This example, which adds elements to a JList after setVisible(), may illustrate the trade-offs.
I was reading through this:
http://www.oracle.com/technetwork/java/painting-140037.html#triggers
And it mentions the following:
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).
The first point is fairly obvious. However, the second and third points leave something to be desired when determining if I need to call repaint(). Almost any example I see calls repaint() whenever a component's graphical properties change at all. However, there is some indication that if I change certain properties I shouldn't have to call repaint(). What might those properties be?
When you have a method that changes a property of the component that affects the way the component will be painted, then that method should invoke repaint(), not the application code. That is the repainting should be hidden from the programmer.
I don't understand what you mean by changing the clipping of the panel. Clipping is something that is done during the painting process. So if you have a property that affects the way you want the painting to be done, you invoke the method that changes that property, that method invokes repaint() and if the clipping area has changed, then your painting routine will use that information while doing the painting.
How to use paint() such that when repaint() is called the previously drawn object should not get deleted when drawing the new object. That is the drawing area must get UPDATED only and not REDRAWN.
In my code when one of many button is clicked, some aplhabet get displayed. I want to have functionality such that when other buttons are clicked the previously drawn alhabets must be present.Take is as if a string of alphabets getting created as the buttons are clicked.
Im using Java Swing for coding.
Some piece of my code:
if(source == btnAlpha[i] )
bollyDraw.repaint(); //bollydraw is an object of a JPanel extended class having implemented the paintComponent(Graphics g) method
In the paint() method:
if (word[i] == key) {
g.drawChars(word, i, 1, x, y);
}
In a project I worked on I used a List to store the objects that were to be drawn as a member of a class. Then as the user interacted with my UI I added/removed items from this list. The JPanel that rendered the items painted the items that were in this list. It's helps separate the UI logic from the paint logic as you can determine what goes into the paint list when an event is fired rather than in the paint method ( which should be as clean as possible ). However this will force you to repaint everything on every paint call.
In conjunction with this Kim's RepaintManager is a great way to limit what gets repainted. It is region based so there is some complexity in determining what region of the screen has changed. If you have the time it is better to use something like this otherwise it could be difficult to add this functionality down the road.
Your app must be prepared to re-paint anything it has painted. From your description, I'm afraid that means you have to keep track of everything you've painted.
The Swing behavior is partially dictated by the underlying window manager and graphical system, which at any time may chose to paint over an area where your application is present. You can override update() to control repaints initiated by your own app, and might be able to improve performance by implementing your own RepaintManager.
This tutorial explains Swing painting in more detail: http://java.sun.com/products/jfc/tsc/articles/painting/
Custom Painting Approaches shows a couple of ways to do this depending on your exact requirement.
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