1

I'm trying to paint a keyboard with keys that are dynamically resizing when the JFrame is resized. Also, the keys can be in different size.

I have a panel which has its layout set to BorderLayout. In the center I put a panel which has its layout set to GridLayout(5,1).

Each row of the grid is a JPanel with FlowLayout. In each of the rows I'm calculating each button and set its preferred size by calling the setPreferredSize method.

When running the program I see only some buttons in a weird appearance. When I'm checking the row panels with getWidth()/getHeight() and with getPreferredSize().width/height, I'm getting different values: For getPrefereedSize().width , I'm getting the width that I really set, but for getWidth() I'm getting a significantly lower value.

Is there a difference between both methods, getWidth() and getPreferredSize().width?

Marco13
  • 53,703
  • 9
  • 80
  • 159
Eitanos30
  • 1,331
  • 11
  • 19

2 Answers2

2

(There is a counterpart of this question: Java: Difference between the setPreferredSize() and setSize() methods in components. And there are some other questions regarding getSize() and getPreferredSize(), but I didn't find one that could be considered as a duplicate. So here we go...)

A component in Swing usually has a preferred size. This is the size that is returned when calling the getPreferredSize method. It is the size that the component would "like" to have, in order to be displayed properly. For example, a JLabel with a certain text and font will have a preferred size that is just large enough to display the whole text.

But when a component is displayed on the screen, then it may not be possible to show it with its preferred size (some reasons will be explained below). So when calling getSize, the method will return the actual size that the component currently has on the screen. When the containing frame is resized, then the component may also be resized, and then return a different value again.

(Note that getSize() basically returns a single object that contains the same values as those returned by getWidth() and getHeight()).


Why it is not always possible make sure that the actual size matches the preferred size:

The layout in Swing is usually handled by layout managers. The details are explained in the tutorial about Laying Out Components Within a Container, but I'll try to summarize the part that is relevant for this question here.

Such layout manager will try to lay out components with their preferred size. One can imagine that this is difficult, and sometimes impossible. Imagine a panel with a GridLayout(1,2) that contains two other panels:

+---------------------+---------------------+
|                     |                     |
|  Preferred Size:    |   Preferred Size    |
|     400 x 300       |      100 x 200      |
|                     |                     |
+---------------------+---------------------+

In the GridLayout, all components must have the same size. But their preferred sizes are different. So the layout manager simply cannot make sure that the actual sizes of the panels are the same as their preferred sizes. So it displays them with a size that is a compromise between the two. (It may also take into account the minimum and maximum size, making it even more difficult...). In the end, the size of both panels may, for example, be (300,200) pixels, even though the preferred sizes have been (400,300) and (100,200) pixels.


Specifically regarding the layout that you described: Note that FlowLayout is a bit special here. It will lay out the components with their preferred size, if there is enough space. If there is not enough space, then some components may not be visible. So you might try changing the FlowLayout in your rows to be a GridLayout(1,n), where n is the number of keys in this row.

Marco13
  • 53,703
  • 9
  • 80
  • 159
  • Thanks. Great answer.. I will defiantly read the to tutorial you attached to your response. About what you said ("changing the FlowLayout to be a GridLayout), Does this layout behaves differently than FlowLayout when there is not enough space for the components? In addition, can you assume why i don't get the paint i am trying? Should i call some container validate method? When the application start i see only some of the keyboard, but all of them are mixed (e.g Tab and Shift are at the same line) and when i'm resizing the frame, also those keyboard disappear – Eitanos30 Aug 05 '19 at 19:08
  • @Eitanos30 The `GridLayout` will "force" the components to the size that is necessary to fit into the "grid cells" (so the components *might* be too small, but will still be visible). Regarding the validation etc.: This should usually not be necessary if you make sure to call `frame.setVisible(true)` **after** everything has been assembled. For more precise help on that, code might be necessary. – Marco13 Aug 05 '19 at 19:47
  • But I set a listener to JFrame resize, so each resize I need to calculate and set the buttons size. After the resizing which method should I call in order to refresh the keyboard buttons? – Eitanos30 Aug 06 '19 at 09:07
  • It should *not* be necessary to attach a listener for the resizing, and it should *not* be necessary to calculate and set the button sizes. This is *exactly* what will mess up your UI, because you're certainly not computing the same results as the layout managers. Just remove this part, and see whether you can achieve the desired layout *solely* relying on layout managers. – Marco13 Aug 06 '19 at 11:23
  • But what will make the button in a different size if i will use the gridLayout instead of using the FlowLayout with the calcaulation of buttons size? – Eitanos30 Aug 06 '19 at 11:30
  • In a `GridLayout`, all "grid cells" will have the same size. If you assign different sizes (by calling `key.setSize(...)`), things will be messed up. If you want components in one row to have different sizes, consider a horizontal `BoxLayout`: https://docs.oracle.com/javase/tutorial/uiswing/layout/box.html . You can hire me for consulting, by the way. – Marco13 Aug 06 '19 at 12:04
  • @camickr Good to know (or bad...) (\*cough\* help-vampire...). Although this question initially wasn't in great shape, I had a quick look and didn't find one specifically about the `getPreferredSize` vs. `getSize` point, so I cleaned it up in the hope to make a somewhat "canonical" answer. But in the end, nothing can replace docs+tutorials and trying things out... :-/ – Marco13 Aug 07 '19 at 21:14
  • @camickr, First of all thanks again. i Had already told you i'm appreciate your help in my first response. I don't know where you live but i'm living in a place where i need to serve in my country's army. When you are in army you don't have access to computer, so i tried to use the site by my phone. As you see i didn't response to any post i had post from last Monday. Now i see the message and immediately accepted it. But if you find it redundant to help me, so don't help me anymore. This site is for helping people and not for getting a medal.Anyway, thanks for the great explanation. – Eitanos30 Aug 11 '19 at 17:52
  • @camickr You seem to be one of the newbies that have to be told: Stack Overflow is *not* a forum ;-P But seriously: One shouldn't immediately accept the first answer. Sometimes, it takes some time for better answers to show and bubble up. Beyond that, of course you're right with keeping a question on a single topic, and not request further and further fixes and extensions in the comments. – Marco13 Aug 11 '19 at 19:03
1

The component's getWidth/getHeight return the current sizes. The getPreferredSize returns what the component would like to get. For example, a button with text will return a preferred size so the text will completely visible.

A reasonable layout manager will ask the child components for their preferred sizes and give them these sizes. This will result in preferred size for the parent component. If the parent component is set a smaller size, it can't enforce the child component's preferred sizes any more and either hides some or makes the components smaller.

Thomas S.
  • 5,804
  • 5
  • 37
  • 72
  • Some references to the respective documentation would be nice – Turing85 Aug 04 '19 at 19:16
  • I hope it is what you meant: https://docs.oracle.com/javase/7/docs/api/javax/swing/JComponent.html#getWidth() and https://docs.oracle.com/javase/7/docs/api/javax/swing/JComponent.html#getPreferredSize() – Eitanos30 Aug 04 '19 at 19:58
  • @Thomas, I have some question that i am not sure i understood: 1.In which situation getWidth/Height will be with the same values as getPreferredSize.getWidth/Height? 2.Can you please explain me what you mean in:"if the parent component is set a smaller size,..it either hides some or makes the components smaller." Did you mean that child settled preferred size won't be the actual size? 3.you said " This will result in preferred size for the parent component",so if parent size will be changed,doesn't it mean the parent container will be large enough to contain all his recalculated childs? – Eitanos30 Aug 04 '19 at 20:15
  • I have rewrite my post, so maybe it will make situation more clear – Eitanos30 Aug 04 '19 at 20:32
  • Unfortunately gridLayout can’t help me here because keys can have a different size. One can be 1.5,1.75,2 times bigger than the other. Therefore I was forced to use the flowLayod for each row in the keyboard – Eitanos30 Aug 06 '19 at 09:05