Java: Difference Between the Setpreferredsize() and Setsize() Methods in Components

Java: Difference between the setPreferredSize() and setSize() methods in components

Usage depends on whether the component's parent has a layout manager or not.

  • setSize() -- use when a parent layout manager does not exist;
  • setPreferredSize() (also its related setMinimumSize and setMaximumSize) -- use when a parent layout manager exists.

The setSize() method probably won't do anything if the component's parent is using a layout manager; the places this will typically have an effect would be on top-level components (JFrames and JWindows) and things that are inside of scrolled panes. You also must call setSize() if you've got components inside a parent without a layout manager.

Generally, setPreferredSize() will lay out the components as expected if a layout manager is present; most layout managers work by getting the preferred (as well as minimum and maximum) sizes of their components, then using setSize() and setLocation() to position those components according to the layout's rules.

For example, a BorderLayout tries to make the bounds of its "north" region equal to the preferred size of its north component---they may end up larger or smaller than that, depending on the size of the JFrame, the size of the other components in the layout, and so on.

setSize() v/s setPreferredSize() and pack()

Calling pack() on a window will size it based on the preferredSize of its containing components. It will be as small as possible but taking into account the preferredSize and layout of its components.
If you just randomly use frame.setSize(), then the components added to the content pane will expand/contract to fit the space available, which means the preferred size of each component may be overridden.

setSize() sets the size of the component and setPreferredSize sets the preferred size.The Layoutmanager will try to arrange that much space for your component.
It depends on whether you're using a layout manager or not ...

See Java: Difference between the setPreferredSize() and setSize() methods in components

What is the difference between getWidth()/getHeight(), and getPreferredSize().width/height?

(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.

Why setting setPreferredSize() on JFrame is bad?

The main reason it would be considered bad (bad is probably too strong a word, unwise might be better) is the use of unknown (magic) numbers, rather than empirical values.

Every platform (and even similar OS running on different hardware and settings) has it's own means for rendering content which can change the amount of space that individual components require.

In regards to things like text fields and text-areas, you can make suggestions about the number of columns (and rows for text areas) which can be used to change a frames final size, using setColumns and setRows for example...

So, using the following code...

import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestLayout101 {

public static void main(String[] args) {
new TestLayout101();
}

public TestLayout101() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

public class TestPane extends JPanel {

private JTextField fullNameTextField = new JTextField(10);
private JTextField emailIDTextField = new JTextField(10);
private JTextArea addressTextArea = new JTextArea(10, 20);
private JButton submitButton = new JButton("Submit");
private JButton cancelButton = new JButton("Cancel");

public TestPane() {

setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.WEST;
gbc.insets = new Insets(4, 4, 4, 4);

add(new JLabel("Full Name: "), gbc);
gbc.gridy++;
add(new JLabel("Email ID: "), gbc);
gbc.gridy++;
gbc.anchor = GridBagConstraints.NORTHWEST;
add(new JLabel("Address: "), gbc);

gbc.gridx++;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1;

add(fullNameTextField, gbc);
gbc.gridy++;
add(emailIDTextField, gbc);
gbc.gridy++;
gbc.weighty = 1;
add(new JScrollPane(addressTextArea), gbc);

JPanel buttons = new JPanel(new FlowLayout(FlowLayout.RIGHT, 4, 4));
buttons.add(submitButton);
buttons.add(cancelButton);

gbc.gridx = 0;
gbc.gridy++;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.weighty = 0;
add(buttons, gbc);
}
}
}

Which produces...

Compact

Now by changing only one line...

private JTextArea addressTextArea = new JTextArea(10, 20);
// Only this value ---^

It produces this...

Mini

And again...

private JTextArea addressTextArea = new JTextArea(10, 40);
// Only this value ---^

Luxury

I could change the number of rows for the JTextArea and effect the height of the window as well.

The difference is, these values are used in combination with the systems font metrics to calculate the preferred size of the components when the program is run, so it will be different for different systems and platforms...

The main point to layouts is to spend your time focused on the intent and the work flow and not trying to get a pixel perfect solution, because there's simply no such thing...talk to web developers, they have the same issues, just much worse (multiple browsers on a single system, all rendering differently)

Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?

  1. Should I completely avoid the use of those methods?

    Yes for application code.

  2. The methods have been defined for a reason. So when should I use them? In which context? For what purposes?

    I don't know, personally I think of it as an API design accident. Slightly forced by compound components having special ideas about child sizes. "Slightly", because they should have implemented their needs with a custom LayoutManager.

  3. What exactly are the negative consequences of using those methods? (I can only think adding portability between systems with different screen resolution.)

    Some (incomplete, and unfortunately the links are broken due to migration of SwingLabs to java.net) technical reasons are for instance mentioned in the Rules (hehe) or in the link @bendicott found in his/her comment to my answer. Socially, posing tons of work onto your unfortunate fellow who has to maintain the code and has to track down a broken layout.

  4. I don't think any LayoutManager can exactly satisfy all desired layout needs. Do I really need to implement a new LayoutManager for every little variation on my layout?

    Yes, there are LayoutManagers powerful enough to satisfy a very good approximation to "all layout needs". The big three are JGoodies FormLayout, MigLayout, DesignGridLayout. So no, in practice, you rarely write LayoutManagers except for simple highly specialized environments.

  5. If the answer to 4 is "yes", won't this lead to a proliferation of LayoutManager classes which will become difficult to maintain?

    (The answer to 4 is "no".)

  6. In a situation where I need to define proportions between children of a Component (for example, child 1 should use 10% of space, child 2 40%, child 3 50%), is it possible to achieve that without implementing a custom LayoutManager?

    Any of the Big-Three can, can't even GridBag (never bothered to really master, too much trouble for too little power).

JComponent setSize() and setLocation() not working

If all you are trying to accomplish is to create a component with dashed border at a specific location then I hope this sample will help get you started

    public class DashTest
{
public static void main(String args[])
{
JFrame frame=new JFrame("Dash Test");

frame.setContentPane(new JPanel(null)); /*A panel with no layout as the main container*/

JButton button=new JButton("Dashed Button");

button.setBorder(BorderFactory.createDashedBorder(Color.red));
/*swing comes inbuilt with custom borders*/


button.setBounds(100,100,150,30);/*set the x,y,width,height of the button works only if you have no layout set as shown above*/

frame.add(button);

frame.setSize(500,500);

frame.setVisible(true);
}
}

For your purpose there is no need to subclass your component to JComponent just for using borders,however if you are trying to do more fancy stuff inside your component and not just a border then you have to override that components paint component method

class MyComponent extends JComponent
{
MyComponent ()
{
super();

setBorder(BorderFactory.createDashedBorder(Color.red));/*keep the red border*/
}

@Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);/*NEVER FORGET THIS*/

Graphics2D g2d=(Graphics2D)g;

/*do more creative stuff now with graphics*/
}
}


Related Topics



Leave a reply



Submit