Why Is It Frowned Upon to Use a Null Layout in Swing

Why is it frowned upon to use a null layout in Swing?

If you layer the layout managers correctly the screen will re-flow to different sizes for you, the idea is to use a single set of layout managers on ALL screen sizes.

If you use null you will have to do each screen size yourself. Not only that but if the app can be windowed you have to support every possible size they might scroll to.

That's kind of difficult to do, but the layout mangers are designed to do just that.

There are some common tricks. BorderLayout is a great layout to start with. Sometimes you might use it at multiple levels--often with just 2 or 3 components in it. That's because it's really good at giving all but one area the minimum required area and giving everything else to the CENTER.

FlowLayout can be useful but it's tricky if your components are different sizes.

I wouldn't try GridBagLayout unless you are planning to write code to feed your layout manager (an excellent solution at that!).

I also wouldn't use GUI builders, they don't know the overall way you want to reflow your layout.

What's wrong with the Null Layout in Java?

The major problem is the complexities involved in trying to make determination about individual platforms with regards to things like fonts and how pixels may be rendered

Even two systems, running the same OS can generate different output due to different hardware drivers and rendering pipelines.

Much of the API has been abstracted in such away that you should never care that one PC is using a DPI of 120 and using DirectX and another is using a DPI of 92 and using OpenGL.

Layout managers remove the developer from the responsibility of having to calculate the size a component (and its child components) at a particular moment in time as well as calculating the relationship between these components and does it in a standardised way.

The core Swing API has been designed to utilise this API, so when a component changes in some way that would represent a change in the size, all the required containers are notified automatically and the entire hierarchy of components can be adjusted as required.

The basic idea of a layout manager is to describe the relation between components on the same container as well as providing information about how much that container might like to have. This allows you to focus on the user-ability follow of the UI rather then trying to spend time trying to update the UI to meet all various possible combinations of hardware and software.

As a former VB developer (no, I'm not proud if it), I can assure you, the most frustrating part of working with it was trying to develop usable, dynamic UIs that didn't look crap on the next clients machine.

Of all the aspects of Swing, the layout management is one of the most welcomed - IMHO

Java Swing Moving Away From Null Layout

The simplest solution that comes to my mind is a BorderLayout for the main panel. Add the textarea to NORTH / PAGE_START. Make another BorderLayout containing the inventory button (WEST / LINE_START) and the location label (EAST / LINE_END). Add that to SOUTH / PAGE_END of the main BorderLayout. Then just add a BoxLayout with vertical alignment to the main BorderLayout's CENTER containing the two buttons. Here's a tutorial for the standard layout managers.


Sample Image

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Insets;
import java.awt.image.BufferedImage;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;

public class Example {

public Example() {
JTextArea textArea = new JTextArea("There is a locked door");
textArea.setRows(5);
textArea.setBorder(BorderFactory.createLineBorder(Color.GRAY));
textArea.setEditable(false);

WhiteButton button1 = new WhiteButton("Go find a key") {
@Override
public Dimension getMinimumSize() {
return new Dimension(200, 25);
}

@Override
public Dimension getPreferredSize() {
return new Dimension(200, 25);
}

@Override
public Dimension getMaximumSize() {
return new Dimension(200, 25);
}
};
WhiteButton button2 = new WhiteButton("Attempt to force the door open");
button2.setMargin(new Insets(0, 60, 0, 60));

JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.Y_AXIS));
buttonPanel.add(button1);
buttonPanel.add(Box.createVerticalStrut(5));
buttonPanel.add(button2);

WhiteButton inventoryButton = new WhiteButton(
new ImageIcon(new BufferedImage(50, 50, BufferedImage.TYPE_INT_RGB)));

JLabel locationLabel = new JLabel("Location: 0");
locationLabel.setVerticalAlignment(JLabel.BOTTOM);

JPanel southPanel = new JPanel(new BorderLayout());
southPanel.add(inventoryButton, BorderLayout.WEST);
southPanel.add(locationLabel, BorderLayout.EAST);

JPanel mainPanel = new JPanel(new BorderLayout(0, 5));
mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
mainPanel.add(textArea, BorderLayout.NORTH);
mainPanel.add(buttonPanel);
mainPanel.add(southPanel, BorderLayout.SOUTH);

JFrame frame = new JFrame("Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new Example();
}
});
}

private class WhiteButton extends JButton {

public WhiteButton() {
setBackground(Color.WHITE);
}

public WhiteButton(String text) {
this();
setText(text);
}

public WhiteButton(ImageIcon icon) {
this();
setIcon(icon);
setBorder(BorderFactory.createLineBorder(Color.GRAY));
}

}

}

What is the purpose of using Java Layout Managers?

When you use a layout, invoking pack() "Causes this Window to be sized to fit the preferred size and layouts of its subcomponents." When you don't, you have to try to calculate the bounds yourself. If (when) you get it wrong, as shown in the somewhat contrived example below, users will blame you—and not without some justification. A related example regarding non-resizable containers is seen here.

image

import java.awt.EventQueue;
import java.awt.FontMetrics;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

/**
* @see https://stackoverflow.com/a/37801762/230513
* @see https://stackoverflow.com/a/12532237/230513
*/
public class Evil {

private static final String S = "Tomorrow's winning lottery numbers: 42, ";
private final JLabel label = new JLabel(S + "3, 1, 4, 1, 5, 9");

private void display() {
JFrame f = new JFrame("Evil");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(null);
FontMetrics fm = label.getFontMetrics(label.getFont());
int w = SwingUtilities.computeStringWidth(fm, S) + 8;
int h = fm.getHeight();
label.setBounds(0, 0, w, h);
f.add(label);
f.setSize(w, h * 3);
f.setLocationRelativeTo(null);
f.setVisible(true);
}

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {

@Override
public void run() {
new Evil().display();
}
});
}
}

JPanel with null layout in JScrollPane - don't see elements

Although I agree completely with @Frakcool about null layout, the problem you are facing has a different source. You should not add components directly into JScrollPane, but into JScrollPane's ViewPort.

The line mainScroll.add(container); should be mainScroll.getViewport().add(container);

Swing text field visibility issue

If you don't want to use a layout manager, you need to set its bounds using JTextField's setBounds(x, y, width, height) method, where x and y are position of the textfield in the JFrame:

tf.setBounds(100 , 100 , 100 , 20 );

First set layout to your frame, then add elements and components to it, like in the full code:

import javax.swing.*;

class Tst
{
public Tst()
{
JTextField tf = new JTextField(10);
tf.setBounds(100 , 100 , 100 , 20 );

JFrame f = new JFrame();

f.setSize(400, 400);
f.setLayout(null);
f.setVisible(true);
f.add(tf);

f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

public static void main(String s[])
{
new Tst();
}
}

JViewports with null Layouts?

Scroll panes only work when the preferred size of the component added to the scroll pane is greater than the size of the scroll pane.

When you use a null layout, the preferred size is 0, so the scroll pane doesn't work. That is why you should use a layout manager. It will determine the preferred size for you.



Related Topics



Leave a reply



Submit