Setting size on JLabel displaces other components in java - java

I am setting a JLabel for the error messages in my program, so initially the label is empty label.setText(""), but when there is an error it should change to something like label.setText("Error, you have entered invalid data...").
If I use setSize(x,y) on the label, it forces other components to displace when error message takes place. But using setPreferredSize(Dimension(x,y))doesn't impact them.
Q1. Why is that?
Q2. What is the difference between setSize(x,y) and setPreferredSize(Dimension(x,y))
Q3. Does it have to do anything with layout?
Thank you in advance for explanation!
P.S. I am using GridBagLayout for positioning my components on the JPanel.

Don’t use the setSize method.
setSize is called by LayoutManagers, like GridBagLayout, to lay out child components. When you call setSize explicitly, you are fighting with the GridBagLayout. Eventually, GridBagLayout will undo your setSize call, when it calls setSize for its own purposes.
In other words, any call to setSize eventually will be wiped out by the parent layout.
setPreferredSize will not be wiped out. Most LayoutManagers, including GridBagLayout, do their best to respect a component’s preferred size.
However, you should not be calling setPreferredSize. Components already have a preferred size by default, and it is almost certainly better than any numbers you can come up with. For instance, a JLabel’s default preferred size is the size which is just large enough to accommodate its text, icon, and borders.
Computing a preferred size is harder than you might think. How many pixels does text use? How many pixels high is a 12 point font? 12 points is not 12 pixels. 12 points is 12⁄72 inch. How many pixels is that? It depends on the user’s monitor and graphics resolution. All of this is known to the Swing rendering system, and JLabel uses all of that information to determine its default preferred size. You should not try to reinvent all of that work, and you should not try to replace that work with something simpler, as it will be inadequate.
If you just let the JLabel keep its preferred size, GridBagLayout will do its best to accommodate that. If the window itself does not have room to display the JLabel’s new text, you probably should call the window’s pack() method after changing the text.
Update: This appears to be an XY problem—you really want a message that you can show and hide.
You want your layout to be big enough to accommodate your message text as soon as you create it. This is typically done with a CardLayout, which lets you place several components on top of each other, with only one of them visible at any given moment. Since you want to show no text at all, initially, you would add an empty JLabel as the first component in the CardLayout, so it is shown by default:
JLabel label = new JLabel("Error, you have entered invalid data...");
CardLayout messageLayout = new CardLayout();
JPanel messagePane = new JPanel(messageLayout);
messagePane.add(new JLabel(), "blank");
messagePane.add(label, "message");
// Do not add label directly to your user interface.
// Add messagePane instead.
mainWindow.add(messagePane);
// ...
// Show message
messageLayout.show(messagePane, "message");
// ...
// Hide message
messageLayout.show(messagePane, "blank");
"message" and "blank" are never seen by the user. They are just unique identifiers for each component (“card”) in the CardLayout. You can make them anything you want.

The setSize() function sets the size not based on any LayoutManager. Thats why you should always use setPrefferedSize() when working with a LayoutManager. setPrefferedSize() firstly tries to be conform with the LayoutManagers dimensions if then possible Java tries to set the size of the Label according to your setPrefferedSize() input.
So yes, it does have anything to do with layout. If possible, you should only use setPrefferedSize() as you are working with layout managers.

Related

Difference end result between setFont and setPreferredSize

In a Layout Manager when I use setPreferedSize it increased the size of JLabel but show only one word like (JLabel = Name) after using setPreferedSize JLabel becomes like N.... But setFont works correctly..
Can anyone tell the exact difference between the behavior of setFont and setPreferredSize?
But setFont works correctly..
Exactly, and that is the only method you should use. When you use the setFont() method, the component is responsible for determining the preferred size. The component will take into account information like the font, text, border to determine it's preferred size.
When you invoke setPreferredSize(), you are telling the component that you know better, which you don't because you are just making a guess. If your guess is too small you see the "..." because there is not enough space to paint the entire text.
Don't use setPreferredSize()!

Get size of JPanel before realizing

I've created JPanel and have already added components into it and I'm going to pass that JPanel to PopUpFactory... So can I get size of JPanel before passing it?
I put Jlabel into it and text after that and I don't know the size of that text...
You can set the preferred size using setPreferredSize(Dimension); e.g.
JPanel pnl = new JPanel(new BorderLayout());
pnl.setPreferredSize(new Dimension(640, 480));
This value will subsequently be obtainable by calling getPreferredSize() and will be used when laying out the component, although note that it is not guaranteed that it will actually be rendered at this size.
Why do you actually require the size prior to rendering it? Typically with Swing programming you don't need to deal with explicit dimensions / sizes as the chosen layout will take care of these specifics for you.
EDIT
To address the OP's query regarding JTextField, one option here it to call the int based constructor that accepts the anticipate number of columns. This causes the text field to be rendered wide enough to support that number of characters.
My second point addresses the comment that the setXXXSize methods should never be called directly and that the developer should rely solely on the LayoutManager. This is not always appropriate - Typically it is necessary to set the preferred size of your main application frame. For example, suppose I were writing a a simple browser application in Swing. The majority of the main frame is a JEditorPane for rendering HTML. If I do not set a preferred size for this component (or the containing frame) and I call pack() the frame is likely to be rendered as small as possible, rather than with sensible dimensions.
JComponents doesn't returns getSize, getLocation, getBounds or getXxxSize if a JComponents hasn't been previously visible on the screen or after call pack()
but why care about that, because usage of (proper and correct) LayoutManager can do that automatically, that reason why LayoutManager exist there, really why care about that
Just call getPreferredSize method for JLabel.No matter if container of it is not realized, preferred size changes if you are setting text of jlabel even before you set it visible.

add()ing to a JPanel breaks its size

I have a JPanel identified by myPanel. I create a series of JButtons, and add() them to myPanel. At the end of my generating-and-adding loop, I call myPanel.validate(). The buttons show up.
The problem is the size of the panel is affected. No matter what Layout Manager I choose, the buttons are always added on the same line (even though there is more space beneath them).
I have tried setting myPanel's maximum size and setting its size after every add(). No matter what I do, after that validate(), the panel is blown up and my application's GUI is screwed.
Any ideas?
I create a series of JButtons, and add() them to myPanel... the buttons are always added on the same line (even though there is more space beneath them).
None of the default layout managers provide automatic wrapping. You need to specify how you want wrapping to occur. A GridLayout or a GridBagLayout can be used in these cases.
Or you can try the Wrap Layout which was written for this purpose.
i would firstly set a preferred size on the jpanel:
myPanel.setPreferredSize(new Dimension(X, Y));
this will tell your layout manager how to try to fit the contents within this dimension.
without seeing your source code, i can't add much more than that.

How to find out the preferred size of a JPanel which is not displayed, according to its content?

I am using a JPanel (with several labels inside) to add a dynamic information on a graph. This panel is dynamically created, it is not visible before I use it to draw.
For this, I am using a BufferedImage, and I follow approximately the same steps as described on this other question. It works good, as long as I specify all sizes (the panel, and its components).
Like asked as well in comments of the referred question, how can I determine the optimal size of this panel? The same operation would be done if this panel was displayed in a regular frame/layout setting.
In my case, how can I "pack", in a way, this panel, so that its size, and size of its content are set to the optimal (determined by the size of labels, then)?
Suraj and willcodejavaforfood put me on the good track.
Checking what is actually done in a pack() method, I see that this is mostly setting the current size to the one returned by getPreferredSize().
From this, I managed to make such solution:
// Creating the panel
JPanel lPanel = new JPanel();
//lPanel.setSize(1000, 1000); //default size, not needed anymore
lPanel.setLayout(new BoxLayout(lPanel, BoxLayout.PAGE_AXIS));
//Adding the content
lPanel.add(new JLabel("Blah"));
// etc...
//Adjust the panel to its preferred size
lPanel.setSize(lPanel.getPreferredSize());
//Call the layout method
//(this will adjust the content components to their correct size and position)
lPanel.doLayout();
This method works correctly, and adjusts the panel and its content to the correct size (and answers my question in a simplistic way: "how to find the preferred size? getPreferredSize()").
However, it requires to set the initial size to a large enough size, so that the content fits in, or they won't be put on the layout. This is a bit pity, and not really "clean", but I can't find a way to avoid that, for now.
Edit: Actually, the default size was not necessary, because getPreferredSize() returns the correct value, even before calling doLayout(). As such, the panel can be set to its proper size before calling the layout method.
The direct answer is to call Window#pack(). This method will automatically set the size of all underlying children to thier preferred sizes(ofcourse this depends on layouts of child containers, for e.g. BorderLayout doesent give a damn about preffered sizes).
So as long as you have set preferred sizes(or min/max sizes in case layouts are like BorderLayout) of your child components, pack() method will be all you need.
[UPDATE]One way is to do is add a HierarchyListener to your jpanel and check for HierarchyEvent#DISPLAYABILITY_CHANGED events. This event is called when your panel is realized that is ready to be shown(and a parent is available), at this moment you can do:
SwingUtilities#getWindowAncestor(myPanel).pack();

Can a layout manager spawn several JPanels?

I have to build a rather large form with many controls. The controls are divided in basic controls/settings and extended controls/settings. The user can decide if he wants to see only the basic or both basic and extended controls.
I've dropped all extended controls onto their own JPanel so that I can easily switch between the two views by showing or hiding this panel.
Currently I'm using GroupLayout and what happens is that the controls on different panels are not aligned:
Label aaa: Text field
Label a: Text field
Label aaaaaa: Text field
----------------------------
Label b: Text field
Label bbb: Text field
Label bb: Text field
Unfortunatly I found now way to "synchronize" the layouts of the two panels (except using AbsoluteLayout and fixed control coordinates)
Is there any way to achive this?
Is my whole design flawed?
EDIT: If it is possible I would like to keep the GroupLayout manager.
As far as I know, no Swing LayoutManager (from JRE or open source) can span several panels.
I am currently working on such a feature (which I called "layouts synchronization") for my DesignGridLayout project, but it is not something easy to implements (I have started about 2 weeks ago and I still don't see exactly if and when I will get to something interesting, but I still have high hope for it;-))
One option you could check would be to add all components to the same panel (with just one GroupLayout then) and hide/show them based on user's selection. Hopefully, GroupLayout will adapt the size to the situation (after calling pack()).
If GroupLayout behaves well, then it would just be a matter of calling pack() each time after user changes his selection to show/hide extended fields.
Else you would have to manually set the size of your panel every time the user changes his selection.
Probably the easiest (good) way to do it is to add all the components to the main panel. Set the subpanels to non-opaque, and add the also to the main panel. The main panel the needs optimised drawing to be switched off.
Another technique is to add a spacer component. To the bottom panel add a component in the same column as the labels which dynamically takes the width component of its various size methods from the top labels. Do the same in reverse to the top panel.
I think there is no way to do it with the standard layout managers. You'll probably have to write your own layout manager, but it shouldn't be too hard if you subclass GroupLayout.
You could use GridLayout instead of GroupLayout which will give you uniform spacing between the columns
If you want to keep them in separate panels with separate layouts:
Iterate over all of the labels that you add, and find the maximum preferred width of each.
Iterate a second time, and set the preferred size to that each label's preferred height, but the maximum width.
This is the explanation of th GridLayout. This will set every component to the size, you expect it. With the GridData object you can specify how the components are ordere.
Examples
(source: sun.com)

Categories