I am just learning Java GUIs, and about layout managers and am looking to create a GUI with the following layout. What would be the best way to approach this? (JFrame is 1000w x 800h)
Here is what I've thought of doing with some success, and a messy solution that doesn't match the wanted layout exactly
JFrame myFrame (GridLayout(2,1))
- JPanel topPanel (BorderLayout)
- JPanel topLeftPanel (GridLayout(9,2) & setSize 666,400)
- JLabel buyingAnInvestment - Jlabel empty1
- JLabel type - JComboBox typeSelect
- JLabel symbol - JTextField symbolField
- JLabel empty2 - JLabel empty3
- JLabel name - JTextField nameField
- JLabel empty4 - JLabel empty5
- JLabel quantity - JTextField quantityField
- JLabel empty6 - JLabel epty7
- JLabel price - JTextField price
- JPanel topRightPanel (GridLayout(2,1) & setSize 333,400)
- JButton reset
- JButton buy
- JPanel bottomPanel (What should I do for this?)
- JLabel messages
- JTextArea & JScrollArea
How would you layout the components and JPanel containers to get the expected result? Any direction would be greatly appreciated.
If the GUI can have Buying an investment & Messages as a TitledBorder, I'd lay it out as follows:
Outer layout - BorderLayout
Buying an investment using a two column GridBagLayout of labels and fields. Put it in the CENTER of the border layout.
Reset / Buy buttons in a single column GridLayout with an ample EmptyBorder and vertical layout padding. Put that panel in the LINE_END of the border layout.
The text area insinde a panel / constraint that will stretch it to full width & height E.G. using another GridLayout in the PAGE_END of the border layout.
(JFrame is 1000w x 800h)
Don't try to guess the size the GUI needs. Layout all the components, then pack() the frame. The GUI will become the smallest size it needs in order to display everything it contains.
This is mostly an elaboration of #AndrewThompson's answer.
The changes and simplifications as compared to your original approach are:
No explicit setSize calls. Instead let the layout-managers choose
the sizes when pack() is called on the JFrame
and when the user resizes it.
There are only 3 panels (as CENTER, EAST and SOUTH part
in a BorderLayout).
The headings "Buy an investment" and "Messages" are implemented as
TitledBorder, not as JLabel.
Using GridBagLayoutinstead of GridLayout, because then you
have much better control by using proper GridBagConstraints
(especially fill, anchor, weightx, weighty, insets).
The above layout was produced by following code:
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(Main::initGUI);
}
private static void initGUI() {
JFrame myFrame = new JFrame("Investment Portfolio");
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setLayout(new BorderLayout());
JPanel topLeftPanel = new JPanel(new GridBagLayout());
myFrame.add(topLeftPanel, BorderLayout.CENTER);
topLeftPanel.setBorder(BorderFactory.createTitledBorder("Buying an investment"));
GridBagConstraints labelConstraints = new GridBagConstraints();
labelConstraints.anchor = GridBagConstraints.WEST;
labelConstraints.gridx = 0;
labelConstraints.gridy = 0;
labelConstraints.weightx = 0.5;
labelConstraints.weighty = 1;
labelConstraints.insets = new Insets(5, 10, 5, 10);
GridBagConstraints fieldConstraints = new GridBagConstraints();
fieldConstraints.anchor = GridBagConstraints.WEST;
fieldConstraints.gridx = 1;
fieldConstraints.gridy = 0;
fieldConstraints.weightx = 0.5;
fieldConstraints.weighty = 1;
fieldConstraints.insets = new Insets(5, 10, 5, 10);
topLeftPanel.add(new JLabel("Type"), labelConstraints);
JComboBox<String> typeSelect = new JComboBox<>(new String[] { "stock", "aaaaaaaa" });
topLeftPanel.add(typeSelect, fieldConstraints);
labelConstraints.gridy++;
topLeftPanel.add(new JLabel("Symbol"), labelConstraints);
JTextField symbolField = new JTextField(10);
fieldConstraints.gridy++;
topLeftPanel.add(symbolField, fieldConstraints);
labelConstraints.gridy++;
topLeftPanel.add(new JLabel("Name"), labelConstraints);
JTextField nameField = new JTextField(20);
fieldConstraints.gridy++;
topLeftPanel.add(nameField, fieldConstraints);
labelConstraints.gridy++;
topLeftPanel.add(new JLabel("Quantity"), labelConstraints);
JTextField quantityField = new JTextField(6);
fieldConstraints.gridy++;
topLeftPanel.add(quantityField, fieldConstraints);
labelConstraints.gridy++;
topLeftPanel.add(new JLabel("Price"), labelConstraints);
JTextField priceField = new JTextField(6);
fieldConstraints.gridy++;
topLeftPanel.add(priceField, fieldConstraints);
JPanel topRightPanel = new JPanel(new GridBagLayout());
topRightPanel.setBorder(BorderFactory.createEmptyBorder());
myFrame.add(topRightPanel, BorderLayout.EAST);
GridBagConstraints buttonConstraints = new GridBagConstraints();
buttonConstraints.fill = GridBagConstraints.HORIZONTAL;
buttonConstraints.insets = new Insets(10, 10, 10, 10);
buttonConstraints.weighty = 1;
buttonConstraints.gridy = 0;
JButton reset = new JButton("Reset");
topRightPanel.add(reset, buttonConstraints);
JButton buy = new JButton("Buy");
buttonConstraints.gridy++;
topRightPanel.add(buy, buttonConstraints);
JPanel bottomPanel = new JPanel(new BorderLayout());
myFrame.add(bottomPanel, BorderLayout.SOUTH);
bottomPanel.setBorder(BorderFactory.createTitledBorder("Messages"));
JTextArea messagesArea = new JTextArea(6, 30);
bottomPanel.add(new JScrollPane(messagesArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS), BorderLayout.CENTER);
myFrame.pack();
myFrame.setVisible(true);
}
}
Related
I know there are some other questions similar to this but I haven't seen my specific question answered. I want to change the size of a JButton WITHOUT changing the look. For example if I use setPreferredSize, I lose the white background color and rounded corners. I just want to remove the surrounding padding so the button is only slightly bigger then it's label.
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame jFrame = new JFrame("Label");
jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = new Insets(10, 10, 10, 10);
JPanel jPanel = new JPanel(new GridBagLayout());
JButton jButtonUp = new JButton("Upd");
//jButtonUp.setPreferredSize(new Dimension(30, 20));
jPanel.add(jButtonUp, gbc);
gbc.gridy = 1;
JButton jButtonDn = new JButton("Del");
//jButtonDn.setPreferredSize(new Dimension(30, 20));
jPanel.add(jButtonDn, gbc);
jFrame.add(jPanel);
jFrame.pack();
jFrame.setVisible(true);
Using Mac OSX Sierra.
What I have is this:
What I get with setPreferredSize is this:
What I want is this:
Check this answer here, Simply do
After the line:
JButton jButtonUp = new JButton("Upd");
Add:
jButtonUp.setBorder(null);
jButtonUp.setMargin(new Insets(0,0,0,0));
Then add the button to the panel:
jPanel.add(jButtonUp, gbc);
I use a GridBagLayout and place a JLabel on it as the picture shows. I managed to set the size of the JLabel to the desired one via ipadx and ipady but I don't seem to work with the position of it. It seems it is always centered on the middle while I'd like to start from the red dot and don't reposition itself as I resize the window. What should I do?
Thanks. The code I use is also:
GridBagLayout gbl = new GridBagLayout();
setLayout(gbl);
GridBagConstraints gbc = new GridBagConstraints();
JLabel jl = new JLabel("This is a jlabel!", SwingConstants.CENTER);
jl.setBorder(BorderFactory.createLineBorder(Color.black));
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.ipadx = 87;
gbc.ipady = 220;
add(jl, gbc);
I improved it... now you can work with insets to position that label around JFrame, but after some research I would recommend to choose different layout manager.
So your code would look like:
Dimension d = new Dimension(350, 400);
GridBagLayout gbl = new GridBagLayout();
JFrame frame = new JFrame("Heloo");
frame.setLayout(gbl);
GridBagConstraints gbc = new GridBagConstraints();
JLabel jl = new JLabel("This is a jlabel!", SwingConstants.CENTER);
jl.setBorder(BorderFactory.createLineBorder(Color.black));
gbc.ipadx = 87;
gbc.ipady = 220;
gbc.insets = new Insets(0, 0, 360, 340);// here work with JFrame size!!
Hope this code will help you :)
I'm making a program that uses a GridBagLayout in a container. My primary use for this is to have two JPanels, which occupy 75% and 25% of the horizontal space of the window. For some reason though, the two panels look more like 90/10, and when resizing, the smaller one rapidly changes in size, between it's apparent minimum size, and what I believe is the desired 25%.
Here is the relevant code.
frmReedreadV = new JFrame();
frmReedreadV.setBounds(x, y, width, height);
frmReedreadV.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmReedreadV.getContentPane().setLayout(new BoxLayout(frmReedreadV.getContentPane(), BoxLayout.Y_AXIS));
JPanel stretchyPanel = new JPanel();
frmReedreadV.getContentPane().add(stretchyPanel);
stretchyPanel.setLayout(new CardLayout(0, 0));
JPanel textAndUsers = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
gbc.weighty = 1;
textArea = new JTextArea();
textArea.setMargin(new Insets(2, 5, 5, 2));
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
textArea.setEditable(false);
scrollPane = new JScrollPane(textArea);
scrollPane.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
gbc.weightx = 0.8;
textAndUsers.add(scrollPane, gbc);
list = new FriendsList(listUpdate);
gbc.weightx = 0.2;
textAndUsers.add(list.frmUserList, gbc);
stretchyPanel.add(textAndUsers);
FriendsList is a JList contained in a JPanel.
There are other buttons and text fields in the main CardLayout content pane, but those shouldn't affect what is inside of this GridBagLayout, correct?
I made another copy of this JPanel as a standalone application, and it displays and resizes perfectly. See here:
JFrame frame = new JFrame();
frame.getContentPane().setLayout((new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS)));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(100, 100, 550, 600);
JPanel stretchyPane = new JPanel();
frame.getContentPane().add(stretchyPane);
stretchyPane.setLayout(new CardLayout(0, 0));
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
JTextArea text = new JTextArea();
text.setMargin(new Insets(2, 5, 5, 2));
JScrollPane panel1 = new JScrollPane(text);
FriendsList panel2 = new FriendsList(new Object());
c.fill = GridBagConstraints.BOTH;
c.weightx = .8;
c.weighty = 1;
panel.add(panel1, c);
c.weightx = .2;
//c.fill = GridBagConstraints.HORIZONTAL;
panel.add(panel2.frmUserList, c);
stretchyPane.add(panel);
frame.setVisible(true);
What could be causing the difference between the two, since I've replicated my original line by line into the copy?
The weightx and weighty properties might appear to act as proportional sizes, but that is not what they do. In fact they determine the distribution of extra space in the layout.
If you set everything to its preferred size by calling pack() on your JFrame, there will be no extra space. Which means the weightx and weighty properties have no effect while it's in that state.
Once the user starts resizing the window to be larger, there will be extra space, and only then will GridBagLayout consult the weightx and weighty properties to determine how to apportion that extra space to each column and row. Until then, it's entirely possible for a component with a small weightx to be wider than a component with a larger weightx, if their preferred sizes dictate it.
Hopefully this simple program will demonstrate this concept. Try using the mouse (or keyboard) to resize the window to be wider, and observe how each of the textfields grows:
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class GridBagProportions {
static void buildAndShowWindow() {
JTextField small = new JTextField("small (0.8)", 5);
JTextField large = new JTextField("LARGE (0.2)", 30);
small.setMinimumSize(small.getPreferredSize());
large.setMinimumSize(large.getPreferredSize());
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets.left = 6;
gbc.insets.top = 6;
gbc.insets.bottom = 6;
gbc.weightx = 0.8;
panel.add(small, gbc);
gbc.weightx = 0.2;
gbc.insets.right = 6;
panel.add(large, gbc);
JFrame frame = new JFrame("GridBagLayout Proportions");
frame.getContentPane().add(panel);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
buildAndShowWindow();
}
});
}
}
So what can be done about it? Well, this is one layout scenario that GridBagLayout cannot do. I would try using a SpringLayout:
SpringLayout layout = new SpringLayout();
JPanel textAndUsers = new JPanel(layout);
SpringLayout.Constraints scrollPaneConstraints =
new SpringLayout.Constraints(scrollPane);
Spring scrollPaneWidth = scrollPaneConstraints.getWidth();
SpringLayout.Constraints listConstraints =
new SpringLayout.Constraints(scrollPaneWidth,
scrollPaneConstraints.getY(),
Spring.scale(scrollPaneWidth, 0.25f),
scrollPaneConstraints.getHeight());
layout.putConstraint(SpringLayout.EAST, textAndUsers, 0,
SpringLayout.EAST, frmUserList);
layout.putConstraint(SpringLayout.SOUTH, textAndUsers, 0,
SpringLayout.SOUTH, scrollPane);
textAndUsers.add(scrollPane, scrollPaneConstraints);
textAndUsers.add(frmUserList, listConstraints);
Notice that the creation of listConstraints specifies a width argument which is Spring.scale(scrollPaneWidth, 0.25f). This ensures the list is always one-fourth as wide as the scrollPane containing the JTextArea.
SpringLayout is tricky to use, in that you have to make sure to link the far edges of the layout container to child components explicitly, because SpringLayout won't grow to accommodate all the child components automatically. That's what the putConstraint calls are doing.
I have a JLabel and I want to set both the height and width to a percentage of the JFrame, say 10%. How can this be achieved in Java? I have the JLabel named look and the JFrame named screen
JFrame screen = new JFrame("Example");
....
JPanel lookReplyGUIPanel = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
JLabel lookx = new JLabel("something");
c.gridx = x+1;
c.gridy = y+1;
lookReplyGUIPanel.add(lookx,c);
Thanks! all help appreciated
I have a JPanel with the following code:
JPanel pane = new JPanel();
pane.setLayout(new GridLayout(3, 2, 10, 30));
final JTextField fileName = new JTextField();
pane.add(fileName);
JButton creater = new JButton("Create File");
pane.add(creater);
JButton deleter = new JButton("Delete File");
pane.add(deleter);
I was wondering, how do I make it so that the JTextField takes up two spaces on the GridLayout, while having the two buttons share a row by taking up one space each on the same line?
It is a hard to do with GridLyout. You have create wider cells (e.g. new GridLayout(2, 2, 10, 30), then add TextField to the fist cell. Then you have to create yet another panel with GridLayout(2, 1), put it into the cell in second line and add your button into 1 st cell of this nested grid layout.
Shortly you need GridLayout into other GridLayout.
There are better tools to implement this. First take a look on GridBagLayout. It is just to be sure that life is not always pick-nick :). Then take a look on alternative solutions like MigLayout. It is not a part of JDK but it really powerful tool that makes your life easier.
You cannot do column spans with GridLayout. I recomend you try GridBagLayout and GridBagConstraints
After trashing the suggestion of 3rd party layouts, and since I possess a malevolent hatred of GBL, I thought it was about to time to 'put my code where my mouth is' for public scrutiny (and trashing).
This SSCCE uses a nested layout.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
class SimpleLayoutTest {
public static void main(String[] args) {
Runnable r = new Runnable() {
public void run() {
JPanel ui = new JPanel( new BorderLayout(20,20) );
// I would go for an EmptyBorder here, but the filled
// border is just to demonstrate where the border starts/ends
ui.setBorder( new LineBorder(Color.RED,15) );
// this should be a button that pops a JFileChooser, or perhaps
// a JTree of the existing file system structure with a JButton
// to prompt for the name of a new File.
final JTextField fileName = new JTextField();
ui.add(fileName, BorderLayout.NORTH);
JPanel buttonPanel = new JPanel(new GridLayout(1, 0, 10, 30));
ui.add(buttonPanel, BorderLayout.CENTER);
JButton creater = new JButton("Create File");
buttonPanel.add(creater);
JButton deleter = new JButton("Delete File");
buttonPanel.add(deleter);
JOptionPane.showMessageDialog(null, ui);
}
};
SwingUtilities.invokeLater(r);
}
}
Take a look at the tutorial on How to Use GridBagLayout.
Sample code:
JPanel pane = new JPanel();
GridBagLayout gridbag = new GridBagLayout();
pane.setLayout(gridbag);
GridBagConstraints c = new GridBagConstraints();
final JTextField fileName = new JTextField();
c.fill = GridBagConstraints.HORIZONTAL;
c.gridwidth = 2;
c.gridx = 0;
c.gridy = 0;
pane.add(fileName, c);
JButton creater = new JButton("Create File");
c.fill = GridBagConstraints.HORIZONTAL;
c.gridwidth = 1;
c.gridx = 0;
c.gridy = 1;
pane.add(creater, c);
JButton deleter = new JButton("Delete File");
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 1;
pane.add(deleter, c);