JPanel.getBounds() unexpected returns 0 - java

I have a class that extends from JFrame.
In its constructor I generate a JPanel:
JPanel contentPane = new JPanel();
contentPane.setBackground(Color.BLACK);
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JOptionPane.showMessageDialog(contentPane, contentPane.getBounds());
I thought with setContentPane, I would fill the whole available space in my JFrame. So it automatically sets the bounds of the JPanel.
I need to get the bounds of the JPanel, but getBounds() returns x = 0, y = 0, width = 0, height = 0.
Other size related methods of the JPanel (like getWidth() etc.) also return 0. If I setBounds() of my JPanel explicit, the methods return my given values.
The curious thing about that is, that the setBackground fills the whole available space in my JFrame. So, the size of my JPanel must be exactly the size of my JFrame. But it doesn´t seem so.
Maybe this problem is caused by the layout manager, like most Container-related problems. But with a layout manager, I also get 0.
I think this is a very dumb question and can be easily solved, but I can´t figure out the problem.
I didn´t find an answer to this in the web, so hopefully didn´t dublicate some post.

The curious thing about that is, that the setBackground fills the whole available space in my JFrame. So, the size of my JPanel must be exactly the size of my JFrame. But it doesn´t seem so.
Actually no, the content pane will be smaller then the frame, because it's contained within the frame decorations. That means the viewable space is the size of the window - the size of the decorations.
Also, a component won't be painted until its sized beyond 0x0
Before the contentPane can know how big it will be, it needs to be laid out by it's parent container. In order for the parent container to lay out the child container(s), it needs to know the size they might like to be.
As you say, this is related to the layout managers, in order for container to know how big it can be, it needs to know how much space it's parent container will give it.
Maybe this problem is caused by the layout manager, like most Container-related problems. But with a layout manager, I also get 0.
A container, even under the management of a layout manager, won't be assigned a size until the parent container is sized appropriately.
While there are several ways to overcome this, the question becomes why? The fact that you're setting the contentPane's layout manager to null is worrisome and would suggest that you're now going to need to reinvent the wheel and replace the job that the layout managers do for you anyway.
I would suggest calling pack before you try and get the component size, but, again, because you've negated the layout manager, this won't result in a value you would be happy with...

Presumably as this is in your main frames constructor you haven't called setVisible(true) on the main frame (the top level window) when you call JOptionPane.showMessageDialog?
If so then the GUI components haven't yet been rendered, so they have bounds of [0, 0]. If you move JOptionPane.showMessageDialog to after setVisible you'll get a dimension.
Alternatively you could call pack to lay things out. As per my comment below you would call contentPane.setPreferredSize(new Dimension(width, height)); before you do this.

Related

JButton size larger than specified

I created a jframe, added a jbutton to it, and set the size of the jframe as 500,500 and size of the jbutton as 40,60. However, when I executed my program, my jbutton was covering the whole of my jframe. I
tried many things and looked into many sources, but I could not find a solution.
Please help me solve this.
You're not using a LayoutManager of any kind. The JButton will try to inherit the size of the parent container, as the default for a JFrame is BorderLayout (specifically, BorderLayout.CENTER). You could try using
button.setPreferredSize(x, y);
However I don't think this would be enough by itself. Call getContentPane on the Jframe, and set a layout on that contentPane container (I use FlowLayout a lot, as it respects setPreferredSize). Put your JButton inside that.
This is always a good starting point:
https://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html
As the methods that you can call on a UI element vary depending on what LayoutManager you're assigning them to (be the child of). Sometimes it's setMinimumSize, sometimes it's setPreferredSize, and sometimes it's a combination.

Setting size on JLabel displaces other components in 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.

Resizing The GUI?

my question is simple but I can not find exact solution for this. I try to write a program with Java GUI, I use absolute layout for my program and I set frame bounds(100, 100, 450, 300) . When I run the program and make it full screen, components stays on their places. I want them to replace automatically according to screen size.
All supports are accepted, thank you!
The solution is quite simple. You state, "I use absolute layout for my program and I set frame bounds(100, 100, 450, 300)." Don't do this. Use the layout managers to help you place your components.
For instance, if you used a BorderLayout for the main JPanel, and added the JButton to a new GridLayout(0, 1, 0, 5) using JPanel (1 column, variable rows, 5 spaces between rows), adding this JPanel to main in the BorderLayout.LINE_END position, your problem is likely solved. As a general rule, you should avoid use of null layout and use of setBounds(...) for component placement as this makes for very inflexible GUI's that while they might look good on one platform look terrible on most other platforms or screen resolutions and that are very difficult to update and maintain.

How to get the bounds of a panel set by Miglayout manager before it is displayed?

There are three different kinds of panel each spanning different number of grids. 1*3 , 1*1 , 3*1 .
add(panel1, "span 1 3,push, grow");
add(panel2, "push, grow");
add(panel3, "span 3 1,push, grow");
I want to change first panel's constraint to "span 1 2" when it overlaps with other panel on the screen. But to find out whether it overlaps with another panel I have to know it's bounds.
I did not set any size constraints.
Is there any way , to know 'the bounds before the panel/component is actually displayed'?
And also, how to know the length of the rows and columns set by the MigLayout manager?
Actually I want to cover the full screen with these differently sized panels.
EDIT :
I forgot to enter the main culprit ...add(lastPanel, span, push, grow)
I am trying to cover the full screen with differently sized panels. This code works for even number of rectangles but not for odd. When they are odd in number, then the last grid is always left empty . So I spanned the last panel to cover the full empty available space, but then it overlapped with the 3*1 panel.
I can think of a couple of ways, not really nice or pretty and all suffer from the same issue.
Layouts can occur repetitively in succession (that is you will be clobbered with a number of request to layout the container in quick succession)
The trap is trying to figure out when it's come to stop. The next problem is known when you've caused it.
You "could" override the parent Containers doLayout method, after you've called super.doLayout you will have access to the resulting layout. This is not the best solution as it requires you to implement the Container which you may not want to to.
The other solution I can think of is using a ComponentListener on panel1 on monitor the componentResized event.
I would seriously play around with these and see what trouble you're getting yourself into. A better solution is to try and work out your layout issues ahead of time.
JPanel (by default valid for every Swing JComponents) returns its Size or Bounds in two cases
if is once time visible on the screen
after pack() to the Top-Level Container
there no reason to know any of this value for Standard LayoutManagers, nor for MigLayout,
I got this similar problem again but this time I got the answer, I might be helpful for someone, so I am posting it here.
addAncestorListener(new AncestorListener() {
#Override
public void ancestorAdded(AncestorEvent event) {
height = getHeight();
width = getWidth();
//Modifications to the components here.
}
I wanted the dimensions set by the LayoutManager at compile time (which was not possibe). The AncestorListener did the trick, as soon as the components were laid out on the screen . It captures the dimensions and modified the components accordingly.

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();

Categories