Vertically center GridBagLayout like BoxLayout - java

I am trying to center components using a GridBagLayout in the same manner that a Box centers components when you use Box.createVerticalGlue(). I initially did use a vertical Box:
Box box = Box.createVerticalBox();
box.add(Box.createVerticalGlue());
box.add(add);
box.add(remove);
box.add(edit);
box.add(Box.createVerticalGlue());
JPanel internalPanel = new JPanel(new BorderLayout());
internalPanel.add(keywordsScrollPane, BorderLayout.CENTER);
internalPanel.add(box, BorderLayout.EAST);
But as you can see, it looks sloppy because my buttons are different sizes:
I decided to switch to GridBagLayout so I can utilize GridBagConstraints.fill. This approach fixes my button width issue, but I cannot figure out how to vertically center the buttons. I changed the grid size and placed the buttons in the middle three rows, but the buttons were still appearing at the top of the panel. I tried making use of GridBagConstraints.anchor and GridBagConstraints.weighty as well. The latter almost worked, but there are very large margins between the buttons:
I am looking for the buttons to be grouped together as they were in my Box approach. How can I achieve this with a GridBadLayout?
I am using a class I created called ConstraintsBuilder which works exactly as you would expect. It's for creating GridBagContraints with nice one-liners. Here is all the (relevant) code for your viewing pleasure:
public class KeywordsDialog extends JDialog implements ActionListener, ListSelectionListener {
private JList<String> keywords;
private JScrollPane keywordsScrollPane;
private JButton add;
private JButton remove;
private JButton edit;
private Set<String> keywordsList;
public KeywordsDialog(Window parent, Collection<String> keywordsList) {
super(parent);
this.keywordsList = keywordsList == null ? new HashSet<String>() : new HashSet<String>(keywordsList);
if (keywordsList != null && !keywordsList.isEmpty()) {
this.keywords = new JList<String>(toListModel(keywordsList));
} else {
this.keywords = new JList<String>(new DefaultListModel<String>());
}
this.keywordsScrollPane = new JScrollPane(keywords);
this.add = new JButton("Add");
this.remove = new JButton("Remove");
this.edit = new JButton("Edit");
this.edit.setEnabled(false);
this.add.setEnabled(false);
ConstraintsBuilder builder = LayoutUtils.gridBagConstraintsBuilder();
JPanel internalPanel = new JPanel(new GridBagLayout());
internalPanel.add(this.keywordsScrollPane, builder.gridX(0).gridY(0).gridHeight(3).margins(0, 0, 0, 5)
.fill(GridBagConstraints.BOTH).weightX(1D).weightY(1D).build());
internalPanel.add(this.add,
builder.reset().gridX(1).gridY(0).fill(GridBagConstraints.HORIZONTAL).weightX(1D).weightY(1D).build());
internalPanel.add(this.remove,
builder.reset().gridX(1).gridY(1).fill(GridBagConstraints.HORIZONTAL).weightX(1D).weightY(1D).build());
internalPanel.add(this.edit,
builder.reset().gridX(1).gridY(2).fill(GridBagConstraints.HORIZONTAL).weightX(1D).weightY(1D).build());
this.keywords.setBorder(BorderFactory.createTitledBorder("Keywords"));
internalPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
this.setLayout(new BorderLayout());
this.add(internalPanel, BorderLayout.CENTER);
Dimension screen = GuiHelper.getScreenSize(parent);
this.setSize((int) (screen.getWidth() / 4), (int) (screen.getHeight() / 3));
this.setLocationRelativeTo(parent);
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
}
// ...
}

Oracle has a helpful tutorial, Creating a GUI With Swing. Skip the Learning Swing with the NetBeans IDE section. Pay particular attention to the How to Use GridBagLayout section.
The easiest way to create this GUI is to treat the JTextArea separately from the JButton area.
Here's the complete runnable code.
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class ExampleGUI implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new ExampleGUI());
}
#Override
public void run() {
JFrame frame = new JFrame("Example GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createTextArea(), BorderLayout.CENTER);
frame.add(createButtonPanel(), BorderLayout.EAST);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JScrollPane createTextArea() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JTextArea textArea = new JTextArea(10, 30);
textArea.setText("keyword");
panel.add(textArea, BorderLayout.CENTER);
return new JScrollPane(panel);
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(0, 5, 5, 5);
gbc.gridy = 0;
JButton button = new JButton("Add");
panel.add(button, gbc);
gbc.gridy++;
button = new JButton("Remove");
panel.add(button, gbc);
gbc.gridy++;
button = new JButton("Edit");
panel.add(button, gbc);
return panel;
}
}

I would make the GUI simpler. Put the three buttons into a JPanel that uses a GridLayout, one declared to use 1 column and variable number of rows, one with a desired spacing between buttons, here, 5 pixels: JPanel buttonPanel = new JPanel(new GridLayout(0, 1, 5, 5)); and then put that JPanel into the center of a another JPanel, and GridBagLayout without constraints works well for this:
JPanel sidePanel = new JPanel(new GridBagLayout());
sidePanel.add(buttonPanel);
and put that JPanel into the right side of a border layout using JPanel. For example:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class FooSwing01 extends JPanel {
public FooSwing01() {
JTextArea textArea = new JTextArea(20, 50);
JScrollPane scrollPane = new JScrollPane(textArea);
JPanel buttonPanel = new JPanel(new GridLayout(0, 1, 5, 5));
int maxButtons = 3;
for (int i = 0; i < maxButtons; i++) {
buttonPanel.add(new JButton("Button " + (i + 1)));
}
JPanel sidePanel = new JPanel(new GridBagLayout());
sidePanel.add(buttonPanel);
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
setLayout(new BorderLayout(5, 5));
add(scrollPane);
add(sidePanel, BorderLayout.LINE_END);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("GUI");
frame.add(new FooSwing01());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}

Related

Need the following UI in Swing

I need the following UI on JFrame. Two Jlabel Vertically Left aligned. Two button horizontally below the Jlabel. I tried below code but it is coming in one row.
Label should be left and vertically aligned.
Button should cover all the width of Jframe.
import javax.swing.*;
import java.awt.*;
public class CustomPanel {
private JFrame frame = new JFrame();
private JPanel basePanel= new JPanel();
public static void main(String []args){
CustomPanel cp= new CustomPanel();
cp.showUI();
}
private void addui(){
JPanel labelPanel = new JPanel();
labelPanel.setLayout(new GridBagLayout());
JLabel label11 = new JLabel("I am here to test");
JLabel label12 = new JLabel("I am here to test row");
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.BOTH;
labelPanel.add(label11, gbc);
gbc.gridy++;
gbc.gridwidth = 2;
labelPanel.add(label12, gbc);
basePanel.add(labelPanel);
/////////////// button panel//////////
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(0, 2, 5, 5));
panel.add(new JButton("Click me"));
panel.add(new JButton("Click me22"));
basePanel.add(panel);
}
private void showUI(){
JFrame.setDefaultLookAndFeelDecorated(true);
addui();
frame.setAlwaysOnTop(true);
frame.setType(Window.Type.UTILITY);
frame.setResizable(true);
frame.getContentPane().setLayout(new BorderLayout());
JScrollPane scrollPane = new JScrollPane(basePanel);
scrollPane.setPreferredSize(new Dimension(400, 250));
frame.getContentPane().add(scrollPane);
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.setSize(500, 300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Oracle has a helpful tutorial, Creating a GUI With Swing. Skip the Learning Swing with the NetBeans IDE section. Pay particular attention to the Laying Out Components Within a Container section.
When creating a Swing GUI, you can break up a complex JPanel layout into more than one simpler JPanels. I created three JPanels for this GUI; the main JPanel, the label JPanel, and the button JPanel.
A Swing application must start with a call to the SwingUtilities invokeLater method. This method ensures that the Swing components are created and executed on the Event Dispatch Thread.
I created the JFrame and the three JPanels in separate methods. This allows me to focus on one part of the GUI at a time and makes the code much easier to read and follow. This also allows me to experiment with different Swing layout managers to see which one is appropriate for the GUI.
Here's the complete runnable code.
import java.awt.BorderLayout;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class CustomPanel implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new CustomPanel());
}
#Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createMainPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
panel.add(createLabelPanel(), BorderLayout.NORTH);
panel.add(createButtonPanel(), BorderLayout.SOUTH);
return panel;
}
private JPanel createLabelPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
JLabel label11 = new JLabel("I am here to test");
panel.add(label11, BorderLayout.NORTH);
JLabel label12 = new JLabel("I am here to test row");
panel.add(label12, BorderLayout.SOUTH);
return panel;
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel(new GridLayout(0, 2, 5, 5));
panel.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
JButton button = new JButton("Click me");
panel.add(button);
button = new JButton("Click me22");
panel.add(button);
return panel;
}
}

How to make the JTextArea fill width and buttonsContainer fill height?

I've tried to use GridBagLayout. It makes the JTextArea parent container occupy a big width, but the text area itself didn't fill the width. Why?
And I hope the first button is close to the top and the second button is close to the bottom. How can I implement it?
Could you please advise how to correct my code?
The following code is all code for the demo.
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
public class Demo extends JFrame {
public Demo() throws HeadlessException {
add(new MainPanel());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
class MainPanel extends JPanel {
private final InputComponent inputComponent = new InputComponent();
private final ButtonsContainer buttons = new ButtonsContainer();
public MainPanel() {
setPreferredSize(new Dimension(800, 100));
setLayout(new GridBagLayout());
setBorder(new EmptyBorder(5, 5, 5, 5));
add(inputComponent,
buildConstraints(0, 0, 1, 1, GridConstraints.FILL_BOTH, 1.0, 1.0));
add(buttons,
buildConstraints(1, 0, 1, 1, GridConstraints.FILL_BOTH, 0.0, 1.0));
}
}
class InputComponent extends JComponent {
private final JTextArea textArea = new JTextArea();
public InputComponent() {
setLayout(new BorderLayout());
textArea.setLineWrap(true);
add(textArea, BorderLayout.CENTER);
}
}
class ButtonsContainer extends JComponent {
private final JButton button1 = new JButton("Button 1");
private final JButton button2 = new JButton("Button 2");
public ButtonsContainer() {
setLayout(new GridBagLayout());
add(button1, buildConstraints(0, 0, 1, 1, GridBagConstraints.HORIZONTAL, 1.0, 0.0));
add(button2, buildConstraints(0, 1, 1, 1, GridBagConstraints.HORIZONTAL, 1.0, 0.0));
}
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
final Demo demo = new Demo();
});
}
private GridBagConstraints buildConstraints(
int x,
int y,
int gWidth,
int gHeight,
int fill,
double weightX,
double weightY
) {
final GridBagConstraints constraints = new GridBagConstraints();
constraints.gridx = x;
constraints.gridy = y;
constraints.gridwidth = gWidth;
constraints.gridheight = gHeight;
constraints.fill = fill;
constraints.weightx = weightX;
constraints.weighty = weightY;
return constraints;
}
}
Original Answer
Oracle has a helpful tutorial, Creating a GUI With Swing. Skip the Netbeans section.
Don't use a GUI builder. You wind up learning the idiosyncracies of the GUI builder, and not learning Java Swing.
I created the following GUI using a JFrame, a main JPanel, and a button JPanel. If you maximize the GUI, you'll see that the JTextArea expands and the JButtons stay towards the top and bottom.
Don't extend Swing components, or any other Java class, unless you want to override one or more of the class methods. Use composition over inheritance.
You can use multiple simple JPanels to create a complex GUI. The GridBagLayout has its uses, like creating a form. But all that was needed was multiple BorderLayouts.
Don't make Swing components class fields unless you need to access the field instance from more than one method.
Organize your code so it reads like an essay, with the most important code towards the top and the more detailed code towards the bottom. Ideally, the reader of your code will never have to page up to find out something. No, the compiler doesn't care about the order of the methods. But human readers sure do.
Here's the complete runnable code.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class ExampleBorerLayoutGUI {
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
new ExampleBorerLayoutGUI();
});
}
public ExampleBorerLayoutGUI() {
JFrame frame = new JFrame("");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.add(createButtonPanel(), BorderLayout.EAST);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createMainPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JTextArea textArea = new JTextArea(5, 40);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
JScrollPane scrollPane = new JScrollPane(textArea);
panel.add(scrollPane, BorderLayout.CENTER);
return panel;
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JButton button1 = new JButton("Button 1");
panel.add(button1, BorderLayout.NORTH);
JButton button2 = new JButton("Button 2");
panel.add(button2, BorderLayout.SOUTH);
return panel;
}
}
Edited to Add
Here's the GUI with three JButtons. You didn't say whether you wanted the third button on the top or the bottom. I chose the top.
I chose a GridLayout for the upper button JPanel. It's easy to add more JButtons to a GridLayout.
Here's the modified complete runnable code.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class ExampleBorderLayoutGUI {
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
new ExampleBorderLayoutGUI();
});
}
public ExampleBorderLayoutGUI() {
JFrame frame = new JFrame("Example Border Layout");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.add(createButtonPanel(), BorderLayout.EAST);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createMainPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JTextArea textArea = new JTextArea(5, 40);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
JScrollPane scrollPane = new JScrollPane(textArea);
panel.add(scrollPane, BorderLayout.CENTER);
return panel;
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.add(createUpperButtonPanel(), BorderLayout.NORTH);
panel.add(createLowerButtonPanel(), BorderLayout.SOUTH);
return panel;
}
private JPanel createUpperButtonPanel() {
JPanel panel = new JPanel(new GridLayout(0, 1, 5, 5));
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JButton button1 = new JButton("Button 1");
panel.add(button1);
JButton button2 = new JButton("Button 2");
panel.add(button2);
return panel;
}
private JPanel createLowerButtonPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JButton button = new JButton("Button 3");
panel.add(button, BorderLayout.SOUTH);
return panel;
}
}
You can auto-generate the right UI code if you use Eclipse IDE's Window Builder:
https://www.eclipse.org/windowbuilder/
It is far easier to design your application that way. Set this up on your IDE and let it do the heavy lifting for you. If you wish to incorporate dynamic resizing of your UI elements, design the code to be responsive.

Java JFrame: Windows Layout & Embed

I need to define a layout for a Jframe Window, as in the picture above.
Below is my approach.
A Picture from my resources folder (/resources/...jpg) embed inside the middle(main).
Top, Bottom, Left and Right divided in four parts, whereas their content is a labeled button stretched, so I can map some methods on it later, that change the picture inside the main container.
I tried to display the picture, but I get the result you see in my screenshot. I can't see it inside my main container and I receive no error message.
I don't know if this is because of my wrong approach of using JFrame.
Below you can see my code, I'd be happy if you could help me solving my wrong design layout pattern too.
MyFrame.java
package ms0.gui;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class MyFrame extends JFrame {
public MyFrame () {
setTitle("This is an example title");
setSize(600,600);
setLocation(750,640);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
//Main Container
Container mainContainer = this.getContentPane();
mainContainer.setLayout(new BorderLayout(8,6));
mainContainer.setBackground(Color.BLUE);
this.getRootPane().setBorder(BorderFactory.createMatteBorder(4, 4, 4, 4, Color.green));
//JButton Positions
JButton topButton = new JButton("Oben");
JButton bottomButton = new JButton("Unten");
JButton leftButton = new JButton("Links");
JButton rightButton = new JButton("Rechts");
//Panel Top
JPanel topPanel = new JPanel();
topPanel.setBorder(new LineBorder(Color.BLACK, 3));
topPanel.setBackground(Color.ORANGE);
topPanel.setLayout(new FlowLayout(5));
topPanel.add(topButton);
mainContainer.add(topPanel, BorderLayout.NORTH);
//Panel Middle
JPanel middlePanel = new JPanel();
middlePanel.setBorder(new LineBorder(Color.black, 3));
middlePanel.setLayout(new FlowLayout(4,4,4));
middlePanel.setBackground(Color.cyan);
//Grid Panel Right
JPanel rightPanel = new JPanel();
rightPanel.setLayout(new FlowLayout(4,4,4));
rightPanel.setBorder(new LineBorder(Color.black, 3));
rightPanel.setBackground(Color.GREEN);
rightPanel.add(rightButton);
//Grid Panel Left
JPanel gridPanel = new JPanel();
gridPanel.setLayout(new GridLayout(4,1,5,5));
gridPanel.setBorder(new LineBorder(Color.black, 3));
gridPanel.setBackground(Color.red);
gridPanel.add(leftButton);
//Center Box
JLabel label = new JLabel("Center Box", SwingConstants.CENTER);
label.setOpaque(true);
label.setBorder(new LineBorder(Color.black,3));
middlePanel.add(gridPanel);
mainContainer.add(label);
mainContainer.add(middlePanel, BorderLayout.WEST);
mainContainer.add(rightPanel, BorderLayout.EAST);
//Panel Bottom
JPanel bottomPanel = new JPanel();
bottomPanel.setLayout(new FlowLayout(3));
bottomPanel.add(bottomButton);
bottomPanel.setBackground(Color.magenta);
bottomPanel.setBorder(new LineBorder(Color.BLUE, 3));
mainContainer.add(bottomPanel, BorderLayout.SOUTH);
//Siegel
String filepath = "/resources/siegel.jpg";
int picWidth = 150;
int picHeight = 150;
ImageIcon image1 = new ImageIcon(getClass().getResource(filepath));
//Image scaledImage = img.getScaledInstance(picWidth, picHeight, Image.SCALE_DEFAULT);
//ImageIcon icon = new ImageIcon(scaledImage);
mainContainer.add(new JButton(image1));
}
}
So, as a very basic example, nothing but BorderLayout
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
public class MyFrame extends JFrame {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
MyFrame frame = new MyFrame();
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public MyFrame() {
setTitle("This is an example title");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new BorderLayout());
add(new JButton("Top button (stretched)"), BorderLayout.NORTH);
add(new JButton("Left button (stretched)"), BorderLayout.WEST);
add(new JButton("Right button (stretched)"), BorderLayout.EAST);
add(new JButton("Bottom button (stretched)"), BorderLayout.SOUTH);
JLabel label = new JLabel("Picture");
label.setBorder(new EmptyBorder(100, 100, 100, 100));
add(label);
}
}
Remember, simple is often best.
Now, if you absolutely, positively must have the label/picture in another container, you can simply make use of GridBagLayout, as it will centre the child component(s) by default, for example...
JLabel label = new JLabel("Picture");
label.setBorder(new EmptyBorder(100, 100, 100, 100));
// Automatic center position
JPanel mainPane = new JPanel(new GridBagLayout());
mainPane.add(label);
add(mainPane);
And you don't have to use EmptyBorder. GridBagLayout will allow to supply insets which will do the same thing

Put 4 JLabel at corners of a JFrame

As the title said, I'm trying to put 4 different JLabels at each of the corners of a JFrame. I want them to stay there forever even if I try to resize the JFrame
I've tried using a layout manager but I just can't get it right.
ImageIcon icon;
JLabel labelNW = new JLabel();
JLabel labelNE = new JLabel();
JLabel labelSW = new JLabel();
JLabel labelSE = new JLabel();
URL buttonURL = InputOutputTest.class.getResource("images/square_dot.gif");
if(buttonURL != null){
icon = new ImageIcon(buttonURL);
labelNW.setIcon(icon);
labelNE.setIcon(icon);
labelSW.setIcon(icon);
labelSE.setIcon(icon);
}
window.add(labelNW, BorderLayout.NORTH);
//window.add(labelNE, BorderLayout.EAST);
//window.add(labelSW, BorderLayout.WEST);
window.add(labelSE, BorderLayout.SOUTH);
This code takes care of the north and south of the left side. I'm probably approaching this wrong though.
I also tried GridLayout (2,2) but they weren't at the corners and there's a huge gap on the right side.
You will want to nest JPanels each using its own layout. In fact you could do this by nesting JPanels that all use BorderLayout.
Going to check if GridBagLayout can do it in one shot.... hang on...
Yep GridBagLayout does it too:
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.*;
public class GridBagExample {
public static void main(String[] args) {
JPanel mainPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0,
GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(
0, 0, 0, 0), 0, 0);
mainPanel.add(new JLabel("Left Upper"), gbc);
gbc.gridx = 1;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.NORTHEAST;
mainPanel.add(new JLabel("Right Upper"), gbc);
gbc.gridx = 0;
gbc.gridy = 1;
gbc.anchor = GridBagConstraints.SOUTHWEST;
mainPanel.add(new JLabel("Left Lower"), gbc);
gbc.gridx = 1;
gbc.gridy = 1;
gbc.anchor = GridBagConstraints.SOUTHEAST;
mainPanel.add(new JLabel("Right Lower"), gbc);
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
}
Edit
Now for the BorderLayout example:
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.*;
public class BorderLayoutExample {
public static void main(String[] args) {
JPanel northPanel = new JPanel(new BorderLayout());
northPanel.add(new JLabel("North East"), BorderLayout.EAST);
northPanel.add(new JLabel("North West"), BorderLayout.WEST);
JPanel southPanel = new JPanel(new BorderLayout());
southPanel.add(new JLabel("South East"), BorderLayout.EAST);
southPanel.add(new JLabel("South West"), BorderLayout.WEST);
JPanel mainPanel = new JPanel(new BorderLayout());
mainPanel.add(northPanel, BorderLayout.NORTH);
mainPanel.add(southPanel, BorderLayout.SOUTH);
JFrame frame = new JFrame("BorderLayout Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
I find that only GroupLayout gives me the control I need for precisely laid out components. This should do the trick. You need to make sure the gap in between has a very large Maximum value (i.e. Short.MAX_VALUE), but you can set the minimum and preferred sizes to whatever you want.
public class LabelFrame extends JFrame {
public LabelFrame() {
JPanel contentPane = new JPanel();
JLabel labelNW = new JLabel();
JLabel labelNE = new JLabel();
JLabel labelSW = new JLabel();
JLabel labelSE = new JLabel();
URL buttonURL = InputOutputTest.class.getResource("images/square_dot.gif");
if(buttonURL != null){
icon = new ImageIcon(buttonURL);
labelNW.setIcon(icon);
labelNE.setIcon(icon);
labelSW.setIcon(icon);
labelSE.setIcon(icon);
}
GroupLayout layout = new GroupLayout(contentPane);
layout.setHorizontalGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(Alignment.LEADING)
.addComponent(labelNW)
.addComponent(labelSW))
.addGap(20,50,Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(Alignment.TRAILING)
.addComponent(labelNE)
.addComponent(labelSE))
);
layout.setVerticalGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(Alignment.LEADING)
.addComponent(labelNW)
.addComponent(labelNE))
.addGap(20,50,Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(Alignment.TRAILING)
.addComponent(labelSW)
.addComponent(labelSE))
);
contentPane.setLayout(layout);
setContentPane(contentPane);
pack();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
LabelFrame frame = new LabelFrame();
frame.setVisible(true);
}
});
}
}
I've tried using a layout manager..
Layout managers are wonderful at what they do, but are perhaps the wrong tool for this job. Consider using a custom border instead. Here is an example.

Resizable Swing layout with buttons arranged according to variable dimensions

I would like to make a layout using Java Swing which looks like the following drawing.
(source: braun-abstatt.de)
On the left is a JPanel which is drawn through paintComponent() in a way that the graphics automatically scale when the window is resized. (The question isn't about that panel. That one's already done.)
Now I need some buttons (the black boxes, added in Photoshop for the drawing) to the right of the JPanel mentioned before. The height of the reddish areas at the top and bottom, next to which there should be just empty space, is calculated along the lines of CONSTANT_FACTOR * getHeight(). Next to each compartment on the left, there should be a group of buttons, lined up to the center of the respective compartment (see the blue lines).
The JPanel containing the buttons knows about the CONSTANT_FACTOR and the number of compartments, so it should be possible to feed this information into a layout manager.
Which layout manager would I best use to achieve this layout? I've read about all the different layout managers, but I can't quite figure out which one or which combination of them best fits in this case.
For example, by use of a different LayoutManager, a very easy and simple container, takes no more than 15-20 minutes:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class ThinLineFrame {
private JFrame frame = new JFrame();
private JScrollPane scrollPane;
private JPanel panel = new JPanel();
private JPanel panelNorth = new JPanel();
private JPanel panelCenter = new JPanel();
private JPanel panelCenterCh1 = new JPanel();
private JPanel panelCenterCh2 = new JPanel();
private JPanel panelCenterCh3 = new JPanel();
private JPanel panelCenterCh4 = new JPanel();
private JPanel panelCenterCh5 = new JPanel();
private JPanel panelSouth = new JPanel();
public ThinLineFrame() {
panelNorth.setBackground(Color.red.darker());
panelNorth.setPreferredSize(new Dimension(80, 30));
//
panelCenter.setBackground(Color.darkGray);
panelCenter.setLayout(new GridLayout(5, 1, 2, 2));
//
panelCenterCh1.setLayout(new BorderLayout());
JButton panelCenterCh1Button = new JButton();
panelCenterCh1.add(panelCenterCh1Button, BorderLayout.CENTER);
//
JButton panelCenterCh2Button1 = new JButton();
JButton panelCenterCh2Button2 = new JButton();
panelCenterCh2.setLayout(new GridLayout(2, 1, 2, 2));
panelCenterCh2.add(panelCenterCh2Button1);
panelCenterCh2.add(panelCenterCh2Button2);
//
JButton panelCenterCh3Button1 = new JButton();
JButton panelCenterCh3Button2 = new JButton();
panelCenterCh3.setLayout(new GridLayout(2, 1, 2, 2));
panelCenterCh3.add(panelCenterCh3Button1);
panelCenterCh3.add(panelCenterCh3Button2);
//
JButton panelCenterCh4Button1 = new JButton();
JButton panelCenterCh4Button2 = new JButton();
panelCenterCh4.setLayout(new GridLayout(2, 1, 2, 2));
panelCenterCh4.add(panelCenterCh4Button1);
panelCenterCh4.add(panelCenterCh4Button2);
//
panelCenterCh5.setLayout(new BorderLayout());
JButton panelCenterCh5Button = new JButton();
panelCenterCh5.add(panelCenterCh5Button, BorderLayout.CENTER);
//
panelCenter.add(panelCenterCh1);
panelCenter.add(panelCenterCh2);
panelCenter.add(panelCenterCh3);
panelCenter.add(panelCenterCh4);
panelCenter.add(panelCenterCh5);
//
panelSouth.setBackground(Color.red.darker());
panelSouth.setPreferredSize(new Dimension(80, 30));
//
panel.setLayout(new BorderLayout(2, 2));
panel.add(panelNorth, BorderLayout.NORTH);
panel.add(panelCenter, BorderLayout.CENTER);
panel.add(panelSouth, BorderLayout.SOUTH);
//
scrollPane = new JScrollPane(panel);
frame.add(scrollPane, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(80, 600));
frame.setLocation(100, 150);
frame.pack();
frame.setVisible(true);
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ThinLineFrame dlg = new ThinLineFrame();
}
});
}
}
You should try looking at MigLayout. It's a super flexible LayoutManager that is also very simple.
The code would look something like:
MigLayout layout = new MigLayout("flowy");
panel.setLayoutManager(layout);
panel.add(button1);
panel.adD(button2);
etc..
Try adding debug, flowy to the constructor to get a visual idea of what is going on.
GBC without an anchor, just with plain vanilla GridBagConstraints and preferred size.
Centered JButton with fixed size:
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
public class MainWithFixSize {
public static void main(String[] argv) throws Exception {
JFrame frame = new JFrame();
Container container = frame.getContentPane();
GridBagLayout gbl = new GridBagLayout();
container.setLayout(gbl);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 1;
JButton component = new JButton();
component.setPreferredSize(new Dimension(25, 25));
gbl.setConstraints(component, gbc);
container.add(component);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(40, 90));
frame.pack();
frame.setVisible(true);
}
private MainWithFixSize() {
}
}

Categories

Resources