I have few questions about layout and paint procedures in SWT.
Fox example, I have a Composite with children. When I invoke composite.layout() what does it mean? Layout? Paint? I find confusing this phrase in the javadoc:
Note: Layout is different from painting. If a child is moved or resized such that an area in the parent is exposed, then the parent will paint. If no child is affected, the parent will not paint.
Another question is, what is going on when I set composite.setLayoutDeferred(true) and invoke after that composite.layout?
Also, what happens when I set composite.setRedraw(false) and after that invoke still the same composite.layout()?
I spent half of my day reading javadoc and doing some practice investigation, but it didn't shed any light on this problem. I can't understand the theory behind this API.
Thanks in advance.
Ok, let me try to explain this:
There are two types of Widgets involved here: Those that can have a layout (Composites and its subclasses) and the other Controls.
When a Paint event occurs, a Composite (if it has a Layout) will cause it's children to repaint. If the children are Composites as well, they will propagate this. If they are other Controls, they will repaint.
Repainting of a Control means that the "state" of this control has changed, i.e. in order to represent its stage properly, it has to do something. This can be caused by a resize event, or by hovering the mouse over it or by clicking on it, basically everything where the visual appearance has to change.
Control#setRedraw(boolean) does exactly what the JavaDoc says:
If the argument is false, causes subsequent drawing operations in the receiver to be ignored. No drawing of any kind can occur in the receiver until the flag is set to true.
The difference to Composite#setLayoutDeferred(boolean) is, that events that occur while it was set to false will be cached and they will be performed, when it is set to true again.
If you call .layout() after you call those methods with true, nothing will happen, if you call them before, the event will take place.
Invoking composite.layout() means to let the set layout manager set the child controls position. Use this if you have changed some properties of the child controls or the configured layout which will influence the layout positions (heavily depends on the layout manager).
Use
control.setRedraw(false);
// other code
control.setRedraw(true);
to improve performance if // other code performs a lot of GUI modifications which would trigger a lot of smaller repaints.
Related
I'm new in Java/SWT. I'm experiencing some troubles using a SWT label.
When I update the text on the label, its size is not correctly updated (the label is cut, respecting the original size). However, if I perform a very small resize in my dialog, the size is updated correctly.
Basically, I create the label with a default text and then, when I load data I update the label with the real text, that is bigger than the original one.
I tried calling label.update() and label.redraw() without luck.
Try to call parent.layout(), where parent is the Composite which contains your label. Also see Understanding Layouts in SWT.
I know this is old, but in order to not lose any LayoutData settings that may be set on the controls. You should call getParent().requestLayout(). The documentation specifically discourages the user of getParent().layout() which loses all the cached Data settings on the controls.
Use of this method is discouraged since it is the least-efficient way to trigger a layout. The use of layout(true) discards all cached layout information, even from controls which have not changed. It is much more efficient to invoke Control.requestLayout() on every control which has changed in the layout than it is to invoke this method on the layout itself.
Based on the documentation of getParent().layout(), you should call requestLayout() on the control itself not its parent as #kingargyle said.
What I always did was label.requestLayout() and it worked flawlessly.
Well, I guess it's for listening to hierarchy changes but I don't really understand what this means in practise.
Anyone has a good real life example when this should/could be used ?
Thanks
David
I used it once.
I was building a bubble-tip(a tooltip but with an arrow pointing to a target component) component. I used JLayeredPane with POPUP_LAYER to implement it.
So whenever the target component changed it's position or resized, I wanted a notification so that i could adjust my tip's arrow to point to it. This is my practical usage of HeirarchyListener. Now why could'y have I used ComponentListener ;)?
One example would be a component that should do something (e.g. display an animation) whenever it becomes visible. Its own visibility attribute is not sufficient, since visibility is inherited. A HierarchyListener allows it to be notified when the inherited visibility status changes.
Also:
http://www.google.com/search?q=%22implements+HierarchyListener%22
I've got a problem, that swing components in different parts of program have sometimes wrong background. For example this or this.
As I mentioned, the bug is not permanent and it can appear in one place one time and never after. But still there are some places, where I can randomly reproduce it. Unfortunately, I don't see any solutions.
Has anyone some ideas how can I fix it?
If you set your components to non-opaque (I think the call is setOpaque(false)), that will let the background colour of the component that it is on top of show through.
in addition to what Paul said, there's the question if you use self made components.
Such components should take care of their complete occupied region (or at least the invalidated regions) in the paint callback. An error seen quite often that leads to strange artifacts when moving or resizing is that only "important" parts are repainted, for example a string to be shown, without drawing the background.
In this case, anything previously blitted ther will show through.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Java Swing revalidate() vs repaint()
Hi all
I'm fighting with my program to make it refresh at the right time.
And not having a lot of success lol
I have 2 questions
Q1: which should I use when my interface has changed: repaint or invalidate?
Q2: when should they be called? I know it sounds stupid but I'm actually having problems because of SwingWorker and other threaded operations.
Q1: which should I use when my
interface has changed: repaint or
invalidate?
If the layout is not up to date because of resizing , font change etc then you should call invalidate. Invalidating a component, invalidates the component and all parents above it are marked as needing to be laid out. Prior to painting, in the validation step if no change is found then the paint step is left out.
If there is some part of component which is being updated (defined by the graphic's clip rectangle, called "damaged" region) then you should consider calling repaint. One of the reason a damaged regions may occur is from the overlapping of a part of your component because of some other component or application.
As per my experience the repaint() is more effective if you call it on the innermost enclosing component (i.e. using public void repaint(int x, int y, int width, int height) rather than using public void repaint()).
Q2: when should they be called?
Invalidate(): marks a component as not valid -- that means, it's layout is or may not be "up to date" anymore: i.e. the component is resized, a border is added, it's font changes, etc. you should never need to call invalidate() by hand, as swing does that for you on pretty much for every property change.
When more than one region within the control needs repainting, Invalidate will cause the entire window to be repainted in a single pass, avoiding flicker caused by redundant repaints. There is no performance penalty for calling Invalidate multiple times before the control is actually repainted.
Repaint() : If the component is a lightweight component, this method causes a call to this component's paint method as soon as possible. Otherwise, this method causes a call to this component's update method as soon as possible.
Also have look at Update method.
NOTE: Swing processes "repaint" requests in a slightly different way from the AWT, although the final result for the application programmer is essentially the same -- paint() is invoked.
Refer to the link below for an excellent link on how painting is done in AWT and Swing:
http://www.oracle.com/technetwork/java/painting-140037.html
Hope this will help.
I'm trying to write an own layout manager.
Components must be placed and sized relative to each other.
This means: when the user drags or resizes an component, some other
components (but not the one altered manually by user) have to
be altered.
Swing tells the layout manager to layout the components every time when
some of them is moved/resized. This is a problem hence the layout
manager itself moves/resizes components:
It fails, the method
layoutContainer(Container parent) is called multiple times.
An example of the whole thing (simplified, in fact my layout manager does
more complex stuff):
[-component1-][-component2-------][-component3-]
user resizes component2 to be smaller, my layout manager would adjust
other components so that all of them would take same space as before:
[-component1-][-component2-][-component3-------]
here, the actions should stop, but they go on: now the layout manager
is invoked because of resizing component3
How could I achieve my intention (in an elegant way)?
Thank you.
EDIT:
Removed threading-related information after suggestions by answerers.
This kind of feedback loop is not uncommon when dealing with events. There are several approaches you can use to break out of this loop and the one I suggest you try is to keep track of the calculated sizes of the components. Then, when you handle the resize event, compare the actual size to the calculated size, and just return without doing anything if they are equal. This is probably the most robust approach as it doesn't depend on the order or frequency of the events. As stated elsewhere you shouldn't need to touch anything related to threads from your layout manager.
This isn't a thread synchronization issue.
You said that when users change the size or location of an object other objects must be altered. I'm guessing that you are listing for some kind of change event so that you can trigger a recalculation of the layout whenever the user changes an object. If so, I'm further guessing that your layout manager is triggering this event, causing it to be invoked again.
Of course, this is only speculation without reviewing your code.
I can't speak to the correct implementation of a layout manager, but as far as threading is concerned, all events in Swing are dispatched on the Swing UI thread, i.e. the same thread. Thus, synchronizing objects will have no effect because only one thread is ever involved. You can see what thread is invoking a method by printing Thread.currentThread() or inspecting it in a debugger.
Depending on what you're trying to do, you may want to take a look at miglayout. I've found it very powerful and easy to use. Correctly implementing a Swing layout manager is a non-trivial task.