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.
Related
My data contained in such as Label and Images is dynamically updated and loaded from the server. How can I refresh or reload them without calling Display.getInstance().callSerially(.)?
If the text in my Label is updated, I'd like to update only that element itself. How can I do that? I can't seem to find any refresh() or reload() method.
Im not so sure, but I think can you add something like this:
yourlabel.repaint();
setText will update the text and repaint. However, if the text size is different layout might change so you will need a revalidate or animateLayout* call to reflow the UI otherwise things might not look as you'd expect in some situations.
If you are on a separate thread (e.g. network callback that isn't on the EDT) you need a callSerially to avoid an EDT violation and hard to detect device bugs.
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.
A lot of web sites these days have an option to let the user increase or decrease the size of the font that appears on the site. I'd like to add similar functionality to my Java Swing app, with an option to change the font to either a larger size or revert to standard size. The user would be able to do this at runtime, via a menu item.
The current version of my code isn't working very well - the code iterates over the keys stored in UIManager/UIDefaults, and for each key that's a Font, my code derives a new font with the target point size (e.g., if it's larger, then the new point size is usually 16; otherwise, if going to regular size, it's usually 11), and then puts that key and new font in UIManager. Afterwards, the code calls SwingUtilities.updateComponentTreeUI() on the frame, and then packs the frame.
The code will increase the font once, but switching back to regular size has no effect. This is especially noticeable with the menu bar.
Am I going about this the right way? Should I instead create a new look and feel with the larger point size, or use some other method entirely?
Thanks in advance for any help.
The code will increase the font once,
but switching back to regular size has
no effect
I believe you need to update the UIManager with a FontUIResource, not just a Font.
Edit:
You should be able to use:
SwingUtilities.updateComponentTreeUI(frame);
Check out the section from the Swing tutorial on Changing the LAF After Startup;
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.
Here's a very specific coding question:
I've recently been asked to maintain some old-ish Java Swing GUI code at work and ran into this problem:
I've attached my own subclass of InputVerifier called MyFilenameVerifier to a JTextField (but it may as well be any JComponent for these purposes). I've overridden the verify() method such that it calls super.verify(input) (where input is the JComponent parameter to verify()). If super.verify(input) comes back false, I do:
input.setBorder(BorderFactory.createLineBorder(Color.RED));
This is a convention used throughout the UI of this application that started long before me, so I don't have a lot of choice as far as using other ways to get the users attention (wish I did). This is just the way it works.
Problem is, once the user goes back and types something valid into the text field, I need a way to set it back to default border (instead of just saying set it to Color.GRAY or whatever, which is a different color from its original border). I need a way to say, "remove the extra decoration and go back to normal" or just set the border to its default, in other words.
Couldn't you just call input.getBorder() and cache it somewhere before setting the border to red?
Or without caching anything, you could tell the JComponent to update its UI back to the look and feel's defaults via component.updateUI. That should make the component reset its colors, borders, fonts, etc to match the original settings.
input.getBorder()
Wouldn't it be awesome if no one ever saw this and I got away free without the ass-beating I deserve for asking this question?
Not sure how your system is build, but I think you can store the original border before changing it. So you can change it back later
// assuming the Border was not null before
if (!super.verify(input)) {
original = input.getBorder();
input.setBorder(...);
} else {
if (original != null) {
input.setBorder(original);
original = null; // not needed
}
}
You need to preserve the existing border when you change it.
One way to do this is to use the methods putClientProperty() and getClientProperty(), which you'll find documented in the API.
Another possibility, if there are only a few input widgets you need this for is to subclass, e.g. JTextField, add setBorderOverride() and modify getBorder() to return "overriddingBorder" if it is not null.
Then you just use setBorderOverride(redBorder) to make it red and setBorderOverride(null) to clear it.
This of course depends on the painting to use getBorder(), which it may or may not do, and which may be implementation specific.
Incidentally, you only need a single static reference to the border-- it's the selfsame border instance used by all JTextFields.