I am working on an application using the Swing GUI widget in Java and am having issues with stretching panels vertically within a panel. My main panel is using the BorderLayout and the problem is in the Center Region. I am using a Panel with a BoxLayout.X_AXIS and inside of it additional Panels with a BoxLayout.Y_AXIS are inserted. I am unable to stretch it vertically from top to bottom. I also want the contents to start from the top to the bottom. I have tried using the GridLayout and it does exactly what I want, however I am constrained width wise because all of the columns are equivalent size and I want some panels to have a smaller width. I have looked at the API, tutorials, and searched Googled for an answer. Any help would be great!
Attached are the code and the screenshot with the layouts.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.util.*;
import java.awt.Color;
public class Colors
{
private JFrame frame;
private JPanel contentPane;
public static void main (String[] args){
Colors gui = new Colors();
gui.start();
}
public void start(){
frame = new JFrame("Words");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
contentPane = (JPanel)frame.getContentPane();
contentPane.setLayout(new BorderLayout(8,8));
center();
east();
frame.pack();
frame.setVisible(true);
}
private void center(){
JPanel centerPanel = new JPanel();
centerPanel.setLayout(new BoxLayout(centerPanel,BoxLayout.X_AXIS));
//centerPanel.setLayout(new GridLayout(1,3));
centerPanel.setPreferredSize(new Dimension(300,0));
centerPanel.setBackground(Color.BLUE);
JLabel oneLabel,twoLabel,threeLabel;
JPanel panelOne = new JPanel();
panelOne.setLayout(new BoxLayout(panelOne,BoxLayout.Y_AXIS));
panelOne.setBackground(Color.CYAN);
oneLabel = new JLabel(" First Label First Column ");
panelOne.add(oneLabel);
twoLabel = new JLabel(" Second Label First Column ");
panelOne.add(twoLabel);
threeLabel = new JLabel(" Third Label First Column ");
panelOne.add(threeLabel);
centerPanel.add(panelOne);
JPanel panelTwo = new JPanel();
panelTwo.setLayout(new BoxLayout(panelTwo,BoxLayout.Y_AXIS));
panelTwo.setBackground(Color.YELLOW);
oneLabel = new JLabel(" 10 ");
panelTwo.add(oneLabel);
twoLabel = new JLabel(" 20 ");
panelTwo.add(twoLabel);
threeLabel = new JLabel(" 30 ");
panelTwo.add(threeLabel);
centerPanel.add(panelTwo);
JPanel panelThree = new JPanel();
panelThree.setLayout(new BoxLayout(panelThree,BoxLayout.Y_AXIS));
panelThree.setBackground(Color.GREEN);
oneLabel = new JLabel(" 10 ");
panelThree.add(oneLabel);
twoLabel = new JLabel(" 20 ");
panelThree.add(twoLabel);
threeLabel = new JLabel(" 30 ");
panelThree.add(threeLabel);
centerPanel.add(panelThree);
contentPane.add(centerPanel, BorderLayout.CENTER);
}
private void east(){
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel,BoxLayout.Y_AXIS));
panel.setPreferredSize(new Dimension(100,150));
panel.setBackground(Color.RED);
JPanel labelPanel = new JPanel();
labelPanel.setBackground(Color.WHITE);
labelPanel.setMaximumSize(new Dimension(26,24));
panel.add(labelPanel);
labelPanel = new JPanel();
labelPanel.setBackground(Color.GREEN);
labelPanel.setMaximumSize(new Dimension(26,24));
panel.add(labelPanel);
contentPane.add(panel, BorderLayout.EAST);
}
}
I have tried using the GridLayout and it does exactly what I want, however I am constrained width wise because all of the columns are equivalent size and I want some panels to have a smaller width
You can try using the GridBagLayout. Each column will be the width of the largest component in the column.
Read the section from the Swing tutorial on How to Use GridBagLayout for more information and working examples.
Another option might be to use a JTable. A JTable allows you to display data in a row/column format. The above tutorial also has a section on How to Use Tables.
Related
Task: make the same window as in the screenshot below using JAVA swing:
What did I do:
Created a panel for the top block (BorderLayout), added two more panels to it (GridLayour), one for the left buttons(FR, FG, FB), the other for the right buttons (A, B,C), added it all to my JFrame window
Created a JScrollPane and added it to the JFrame too
Created a panel for the bottom block (BorderLayout), added two more panels to it (GridLayour), one for the left buttons(1,2,3,4...), the other for the JTextFiel text field, added it all to my JFrame window.
The result is below:
I tried using other layouts, but it still doesn't work. I attach the code.
import javax.swing.*;
import java.awt.*;
public class MyJFrame extends JFrame {
JPanel pan1 = new JPanel();
JPanel pan2 = new JPanel();
JPanel pan3 = new JPanel();
JPanel pan4 = new JPanel();
JPanel pan5 = new JPanel();
JPanel pan6 = new JPanel();
JButton jButton1 = new JButton("FR");
JButton jButton2 = new JButton("FG");
JButton jButton3 = new JButton("FB");
JButton jButton4 = new JButton("A");
JButton jButton5 = new JButton("B");
JButton jButton6 = new JButton("C");
public MyJFrame(){
super("Simple Swing App");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocation(650,300);
setLayout(new GridLayout(3,2));
setResizable(true);
JScrollPane scrollPane = new JScrollPane();
jButton1.setBackground(Color.red);
jButton2.setBackground(Color.green);
jButton3.setBackground(Color.blue);
pan1.setLayout(new GridLayout(1,3,2,2));
pan2.setLayout(new GridLayout(1,3,2,2));
pan3.setLayout(new BorderLayout());
pan4.setLayout(new GridLayout(3,3,2,2));
pan5.setLayout(new GridLayout(3,1,1,1));
pan6.setLayout(new BorderLayout());
pan1.add(jButton1);
pan1.add(jButton2);
pan1.add(jButton3);
pan2.add(jButton4);
pan2.add(jButton5);
pan2.add(jButton6);
pan3.add(pan1, BorderLayout.WEST);
pan3.add(pan2, BorderLayout.EAST);
for (int i=1; i<10; i++) {
JButton jButton = new JButton(i+"");
pan4.add(jButton);
}
for (int i=1; i<4; i++){
JTextField jTextField = new JTextField(" Pole tekstowe " + i + " typu jTextField ");
jTextField.setBackground(Color.WHITE);
jTextField.setBorder(BorderFactory.createLineBorder(Color.CYAN));
pan5.add(jTextField);
}
pan6.add(pan4, BorderLayout.WEST);
pan6.add(pan5, BorderLayout.EAST);
add(pan3);
add(scrollPane);
add(pan6);
setSize(700,450);
setVisible(true);
}
}
If the question is "How to make this GUI?" I would use this approach:
3 x BorderLayout (red) - one for the entire GUI, one each for the PAGE_START and PAGE_END constraints of the main GUI panel.
In the panel used in the PAGE_START, 2 x FlowLayout (green), one in the LINE_START, the other in the LINE_END. (1)
In the panel in the PAGE_END, 2 x GridLayout (blue), the first a 3 x 3, the other a single column.
If the components at the top (the groups of buttons on the left & right) need to be the exact same size, also use grid layouts for them.
I've ran into a pretty annoying problem. The JPanel is adding a vertical gap between components, and I need to get rid of that.
I'm trying to get this (Blue lines are the space I want to get rid of):
To look like this:
Here is my current class:
public class SummaryPanel extends JPanel
{
private JLabel bagelLabel;
private JLabel toppingLabel;
private JLabel coffeeLabel;
private JLabel shotsLabel;
private JLabel subtotal;
private JLabel tax;
private JLabel total;
private JPanel selectionsPanel;
private JPanel totalPanel;
public SummaryPanel()
{
bagelLabel = new JLabel("No bagel $0.00");
toppingLabel = new JLabel("No topping $0.00");
coffeeLabel = new JLabel("No coffee $0.00");
shotsLabel = new JLabel("(Includes 0 shots) $0.00");
subtotal = new JLabel("");
tax = new JLabel("");
total = new JLabel("");
setLayout(new GridLayout(2,1));
selectionsPanel = new JPanel();
selectionsPanel.setLayout(new GridLayout(4,1));
selectionsPanel.add(bagelLabel);
selectionsPanel.add(toppingLabel);
selectionsPanel.add(coffeeLabel );
selectionsPanel.add(shotsLabel );
totalPanel = new JPanel();
totalPanel.setLayout(new GridLayout(3,1));
totalPanel.add(subtotal);
totalPanel.add(tax);
totalPanel.add(total);
totalPanel.setVisible(false);
add(selectionsPanel);
add(totalPanel);
}
}
Its controlled by the layout manager.
setLayout(new GridLayout(2,1));
You are using a GridLayout so each of the two components gets the same space.
selectionsPanel.setLayout(new GridLayout(4,1));
In turn each JLabel get a quarter of the total space available to each panel.
Instead you could use a BorderLayout:
//setLayout(new GridLayout(2,1));
setLayout(new BorderLayout);
Then when you add components to the panel you use:
add(selectionsPanel, BorderLayout.PAGE_START);
add(totalsPanel, BorderLayout.PAGE_END);
Now the preferred sizes will be respected.
The GridLayout will divide the panel into the number of rows and columns specified, and each component will fill one of these cells in their entirety.
You may wish to consider using a BoxLayout instead. This will allow you to stack your components without them expanding unpleasantly.
I'm trying to build a simple panel which I will throw some fields onto and capture some user data. I typically use a combination of GridBagLayouts (thanks to trashgod) and BoxLayouts to achieve the layout I want. I normally don't have any issues with using them and they just do what makes intuitive sense 99% of the time, but I can't seem to make this rather simple panel function properly. Can anyone tell me why?
The panel class:
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class EmailPanel extends JPanel {
private JButton m_OkButton;
private JPanel m_MainPanel;
private JTextField m_ServerIPTF;
private JTextField m_ServerPortTF;
private JTextField m_DomainNameTF;
private JTextField m_UnitNameTF;
private JTextField m_Recipient1TF;
private JTextField m_Recipient2TF;
private final Dimension LARGE_TEXTFIELD_SIZE = new Dimension(125, 25);
public EmailPanel() {
init();
}
private void init() {
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
JPanel tPanel;
JLabel tLabel;
Header: {
tPanel = new JPanel();
tPanel.setLayout(new BoxLayout(tPanel, BoxLayout.X_AXIS));
tPanel.add(Box.createHorizontalGlue());
tLabel = new JLabel("Email Settings");
tPanel.add(tLabel);
tPanel.add(Box.createHorizontalGlue());
tPanel.setBorder(BorderFactory.createMatteBorder(0, 0, 3, 0, Color.red));
this.add(tPanel);
}
MainPanel: {
m_MainPanel = new JPanel();
m_MainPanel.setLayout(new BoxLayout(m_MainPanel, BoxLayout.Y_AXIS));
m_MainPanel.add(Box.createVerticalStrut(5));
tPanel = new JPanel();
tPanel.setLayout(new BoxLayout(tPanel, BoxLayout.X_AXIS));
tPanel.add(Box.createHorizontalStrut(3));
tLabel = new JLabel("Server IP Address:");
tPanel.add(tLabel);
tPanel.add(Box.createHorizontalStrut(3));
m_ServerIPTF = new JTextField();
m_ServerIPTF.setMinimumSize(LARGE_TEXTFIELD_SIZE);
m_ServerIPTF.setMaximumSize(LARGE_TEXTFIELD_SIZE);
m_ServerIPTF.setPreferredSize(LARGE_TEXTFIELD_SIZE);
tPanel.add(m_ServerIPTF);
tPanel.add(Box.createHorizontalStrut(25));
tLabel = new JLabel("Server Port");
tPanel.add(tLabel);
tPanel.add(Box.createHorizontalStrut(3));
m_ServerPortTF = new JTextField();
m_ServerPortTF.setMinimumSize(LARGE_TEXTFIELD_SIZE);
m_ServerPortTF.setMaximumSize(LARGE_TEXTFIELD_SIZE);
m_ServerPortTF.setPreferredSize(LARGE_TEXTFIELD_SIZE);
tPanel.add(m_ServerPortTF);
tPanel.add(Box.createHorizontalGlue());
m_MainPanel.add(tPanel);
m_MainPanel.add(Box.createVerticalStrut(5));
tPanel = new JPanel();
tPanel.setLayout(new BoxLayout(tPanel, BoxLayout.X_AXIS));
tPanel.add(Box.createHorizontalStrut(6));
tLabel = new JLabel("Domain Name:");
tPanel.add(tLabel);
tPanel.add(Box.createHorizontalStrut(3));
m_DomainNameTF = new JTextField();
m_DomainNameTF.setMinimumSize(LARGE_TEXTFIELD_SIZE);
m_DomainNameTF.setMaximumSize(LARGE_TEXTFIELD_SIZE);
m_DomainNameTF.setPreferredSize(LARGE_TEXTFIELD_SIZE);
tPanel.add(m_DomainNameTF);
tPanel.add(Box.createHorizontalGlue());
m_MainPanel.add(tPanel);
this.add(m_MainPanel);
}
OKButton: {
m_OkButton = new JButton("Ok");
tPanel = new JPanel();
tPanel.setLayout(new BoxLayout(tPanel, BoxLayout.X_AXIS));
tPanel.add(Box.createHorizontalGlue());
tPanel.add(m_OkButton);
tPanel.add(Box.createHorizontalGlue());
this.add(tPanel);
}
this.add(Box.createVerticalGlue());
}
}
If you add this to / use this as a content pane, you will see that there are large gaps on the Y axis between the various controls. I'm under the impression that the vertical glue that I add at the end of the init method should grow to consume all the space below the OK button, and the controls would be pushed together as a consequence. What I'm seeing is that it seems to be splitting up the space evenly between the various instances of my temporary JPanel object tPanel and the vertical glue at the bottom. How do I make it stop doing that?
Edit: It seems that the behavior is the same both with and without the somewhat superfluous m_MainPanel object.
This is what I see when it renders and the form is made larger than needed for the controls. I would expect the vertical glue to fill the space below the OK button to keep the controls on the top of the form.
I copy-pasted your code and added the main method:
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.getContentPane().add(new EmailPanel());
frame.pack();
frame.setVisible(true);
}
This is the result:
with or without the line this.add(Box.createVerticalGlue());
Is this what you wanted or not?
Edit: Solution
I edited your code to achieve the desired result:
public class EmailPanel extends JPanel {
private JButton okButton;
private JTextField serverIPTF;
private JTextField serverPortTF;
private JTextField domainNameTF;
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.getContentPane().add(new EmailPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setMinimumSize(frame.getPreferredSize());
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public EmailPanel() {
init();
}
private void init() {
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
JPanel tPanel;
JLabel tLabel;
// Header
tLabel = new JLabel("Email Settings", JLabel.CENTER);
tLabel.setAlignmentX(CENTER_ALIGNMENT);
tLabel.setMaximumSize(new Dimension(Integer.MAX_VALUE, tLabel.getPreferredSize().height));
tLabel.setBorder(BorderFactory.createMatteBorder(0, 0, 3, 0, Color.red));
add(tLabel);
// Fields
JPanel fieldsPanel = new JPanel();
fieldsPanel.setLayout(new BoxLayout(fieldsPanel, BoxLayout.Y_AXIS));
fieldsPanel.setBorder(BorderFactory.createMatteBorder(5, 3, 5, 3, new Color(0, 0, 255, 255)));
// Top fields
serverIPTF = new JTextField(10);
serverIPTF.setMaximumSize(serverIPTF.getPreferredSize());
serverPortTF = new JTextField(10);
serverPortTF.setMaximumSize(serverPortTF.getPreferredSize());
tPanel = new JPanel();
tPanel.setLayout(new BoxLayout(tPanel, BoxLayout.X_AXIS));
tPanel.add(new JLabel("Server IP Address:"));
tPanel.add(Box.createRigidArea(new Dimension(3, 0)));
tPanel.add(serverIPTF);
tPanel.add(Box.createRigidArea(new Dimension(25, 0)));
tPanel.add(new JLabel("Server Port"));
tPanel.add(Box.createRigidArea(new Dimension(3, 0)));
tPanel.add(serverPortTF);
tPanel.add(Box.createHorizontalGlue());
fieldsPanel.add(tPanel);
fieldsPanel.add(Box.createRigidArea(new Dimension(0, 5)));
// Lower field
domainNameTF = new JTextField(10);
domainNameTF.setMaximumSize(domainNameTF.getPreferredSize());
tPanel = new JPanel();
tPanel.setLayout(new BoxLayout(tPanel, BoxLayout.X_AXIS));
tPanel.add(new JLabel("Domain Name:"));
tPanel.add(Box.createRigidArea(new Dimension(3, 0)));
tPanel.add(domainNameTF);
tPanel.add(Box.createHorizontalGlue());
fieldsPanel.add(tPanel);
add(fieldsPanel);
// OK Button
okButton = new JButton("OK");
okButton.setAlignmentX(CENTER_ALIGNMENT);
add(okButton);
}
}
Explanation:
BoxLayout says:
When a BoxLayout lays out components from top to bottom, it tries to size each component at the component's preferred height. If the vertical space of the layout does not match the sum of the preferred heights, then BoxLayout tries to resize the components to fill the space. The components either grow or shrink to fill the space, with BoxLayout honoring the minimum and maximum sizes of each of the components. Any extra space appears at the bottom of the container.
(emphasis mine)
Which tells us that if we restrict the components' maximum height to their preferred height, all the extra vertical space will go to the bottom, just as you want. Hence, we added for all the text fields (the labels do not grow vertically) the line:
nameTF.setMaximumSize(nameTF.getPreferredSize());
and we don't need any vertical glue.
Notes:
I created the text fields with 10 columns, you can change this value.
The top label does not need horizontal glue to stretch it, just relax the maximum width constraint and set the alignment (similarly to the bottom button).
Instead of creating a lot of rigid areas (you used struts), I created a border with the appropriate widths. It is blue for visual purposes, but you should set its alpha to 0 to make is transparent.
Use createRigidArea instead of createXXXStrut (see the note in the above link).
I used frame.setMinimumSize(frame.getPreferredSize()) to not let the window resize to a smaller size than its contents. This is optional.
Non-final fields and variables should not use underscore (_) in the name according to Java naming conventions.
You did not specify horizontal stretching behavior, so it does whatever it does.
I still think that box layout is not the best approach here, or at least do not allow resizing of the window at all (so to not deal with extra space).
I'm trying to draw a gui like shown in the figure, but somehow I'm not able to place the objects in right place (I guess that the problem is with the layout) the textArea is suppose to go in the middle... but is not showing at all
package Chapter22Collections;
import javax.swing.*;
import java.awt.*;
public class Exercise226 extends JFrame {
private JButton jbSort;
private JButton jbReverse;
private JButton jbAdd;
private JButton jbShuffle;
private JLabel jlAddnum;
private JTextArea jTextDisplay;
private JTextField jTextAdd;
public Exercise226() {
jbSort = new JButton("Sort");
jbReverse = new JButton("Reverse");
jbShuffle = new JButton("Shuffle");
jbAdd = new JButton("Add");
jlAddnum = new JLabel("Add number here: ");
jTextDisplay = new JTextArea();
jTextAdd = new JTextField(8);
setLayout(new BorderLayout());
JPanel p1 = new JPanel(new GridLayout(1,3));
p1.add(jlAddnum);
p1.add(jTextAdd);
p1.add(jbAdd);
JPanel p2 = new JPanel(new GridLayout(1,3));
p2.add(jbSort);
p2.add(jbReverse);
p2.add(jbShuffle);
add(p1, BorderLayout.NORTH);
add(jTextDisplay, BorderLayout.CENTER);
add(p2, BorderLayout.SOUTH);
}
public static void main(String... args) {
Exercise226 gui = new Exercise226();
gui.setTitle("Numbers");
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gui.setSize(300, 200);
gui.setLocationRelativeTo(null);
gui.setVisible(true);
}
}
The JTextArea is actually where you expect it to be but has no outline border. It is usual to place the component in a JScrollPane which will give this effect:
add(new JScrollPane(jTextDisplay), BorderLayout.CENTER);
or simply
add(new JScrollPane(jTextDisplay));
To make the textArea re-size with the window, try BoxLayout. Box is "A lightweight container that uses a BoxLayout object as its layout manager."
Box p1 = new Box(BoxLayout.X_AXIS);
How could I add spacing/padding between the elements in the frame? So the text area is more visible and centered.
Borders and padding. E.G.
Compared with:
import javax.swing.*;
import java.awt.*;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
public class Exercise226 {
private JButton jbSort;
private JButton jbReverse;
private JButton jbAdd;
private JButton jbShuffle;
private JLabel jlAddnum;
private JTextArea jTextDisplay;
private JTextField jTextAdd;
private JPanel gui;
public Exercise226() {
gui = new JPanel(new BorderLayout(5,5));
jbSort = new JButton("Sort");
jbReverse = new JButton("Reverse");
jbShuffle = new JButton("Shuffle");
jbAdd = new JButton("Add");
jlAddnum = new JLabel("Add number here: ");
// set the size constraints using columns/rows
jTextDisplay = new JTextArea("Here I am!", 6,20);
jTextAdd = new JTextField(8);
JPanel p1 = new JPanel(new GridLayout(1,3,3,3));
p1.add(jlAddnum);
p1.add(jTextAdd);
p1.add(jbAdd);
JPanel p2 = new JPanel(new GridLayout(1,3,3,3));
p2.add(jbSort);
p2.add(jbReverse);
p2.add(jbShuffle);
JPanel textAreaContainer = new JPanel(new GridLayout());
textAreaContainer.add(new JScrollPane(jTextDisplay));
textAreaContainer.setBorder(new TitledBorder("Text Area Here"));
gui.add(p1, BorderLayout.PAGE_START);
gui.add(textAreaContainer, BorderLayout.CENTER);
gui.add(p2, BorderLayout.PAGE_END);
gui.setBorder(new EmptyBorder(4,4,4,4));
}
public Container getGui() {
return gui;
}
public static void main(String... args) {
JFrame f = new JFrame();
Exercise226 gui = new Exercise226();
f.setContentPane(gui.getGui());
f.setTitle("Numbers");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.pack();
f.setLocationByPlatform(true);
f.setVisible(true);
}
}
This code:
Primarily provides 'white space' in the GUI using different constructors for the layouts that accept 2 int arguments for horizontal & vertical spacing.
Also adds 2 borders:
An empty border around the entire GUI to provide some spacing between it and the frame decorations.
A titled border around the text area, to make it very obvious.
Does implement a change for one unnecessary part of the original code. Instead of extending frame, it simply retains an instance of one.
Uses the JScrollPane container for the text area, as suggested by #Reimeus. It adds a nice beveled border of its own to an element that needs no scroll bars.
Creates a textAreaContainer specifically so that we can set a titled border to surround the scroll pane - without interfering with its existing border. It is possible to use a CompoundBorder for the scroll pane that consists of the existing border (scroll.getBorder()) & the titled border. However that gets complicated with buttons & other elements that might change borders on selection or action. So to set an 'outermost border' for a screen element (like the text area here) - I generally prefer to wrap the entire component in another container first.
Does not create and show the GUI on the EDT. Swing GUIs should be created and modified on the EDT. Left as an exercise for the user. See Concurrency in Swing for more details.
Old Code
The original code on this answer that provides the 'comparison GUI image' seen above. IT is closely based on the original code but with the text area wrapped in a scroll pane (and gaining a beveled border because of that) & given some text to display.
import javax.swing.*;
import java.awt.*;
public class Exercise226 extends JFrame {
private JButton jbSort;
private JButton jbReverse;
private JButton jbAdd;
private JButton jbShuffle;
private JLabel jlAddnum;
private JTextArea jTextDisplay;
private JTextField jTextAdd;
public Exercise226() {
jbSort = new JButton("Sort");
jbReverse = new JButton("Reverse");
jbShuffle = new JButton("Shuffle");
jbAdd = new JButton("Add");
jlAddnum = new JLabel("Add number here: ");
// set the size constraints using columns/rows
jTextDisplay = new JTextArea("Here I am!", 6,20);
jTextAdd = new JTextField(8);
setLayout(new BorderLayout());
JPanel p1 = new JPanel(new GridLayout(1,3));
p1.add(jlAddnum);
p1.add(jTextAdd);
p1.add(jbAdd);
JPanel p2 = new JPanel(new GridLayout(1,3));
p2.add(jbSort);
p2.add(jbReverse);
p2.add(jbShuffle);
add(p1, BorderLayout.NORTH);
add(new JScrollPane(jTextDisplay), BorderLayout.CENTER);
add(p2, BorderLayout.SOUTH);
}
public static void main(String... args) {
Exercise226 gui = new Exercise226();
gui.setTitle("Numbers");
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//gui.setSize(300, 200);
gui.pack();
//gui.setLocationRelativeTo(null);
gui.setLocationByPlatform(true);
gui.setVisible(true);
}
}
I want to create a JInternalFrame with some components in it.
My aim is to design a bash console in Java.
My frame is made of 4 components:
JTextArea included into a JScrollPane
JLabel with the text "Cmd:"
JTextField
JButton with the text "Send"
And I have the following code:
Box box = Box.createHorizontalBox();
box.add(Box.createVerticalStrut(5));
box.add(this.cmd_label);
box.add(Box.createVerticalStrut(5));
box.add(this.cmd_input);
box.add(Box.createVerticalStrut(5));
box.add(this.submit);
box.add(Box.createVerticalStrut(5));
Box mainBox = Box.createVerticalBox();
mainBox.add(Box.createHorizontalStrut(5));
mainBox.add(this.result_scroll);
mainBox.add(Box.createHorizontalStrut(5));
mainBox.add(box);
mainBox.add(Box.createHorizontalStrut(5));
add(mainBox);
So when the frame has not been maximized, I have a correct look:
But when I maximize it, all components are incorrectly located:
So, here is my question: How can I set a weight to the components to fix their location every time, or, how can I fix it?
Thanks.
I think this would be better done with a BorderLayout. In a BorderLayout, the component specified as the center component will expand to fill as much space as possible, and the other components will remain at their preferred sizes.
int hgap = 5;
int vgap = 5;
internalFrame.getContentPane().setLayout(new BorderLayout(hgap, vgap));
internalFrame.getContentPane().add(this.result_scroll, BorderLayout.CENTER);
JPanel bottomPanel = new JPanel();
bottomPanel.add(this.cmd_label);
bottomPanel.add(this.cmd_input);
bottomPanel.add(this.submit);
internalFrame.getContentPane().add(bottomPanel, BorderLayout.SOUTH);
Here try this code, is this behaviour exceptable :
import java.awt.*;
import javax.swing.*;
public class LayoutExample
{
private void createAndDisplayGUI()
{
JFrame frame = new JFrame("LAYOUT EXAMPLE");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel centerPanel = new JPanel();
centerPanel.setLayout(new BorderLayout(5, 5));
centerPanel.setBorder(
BorderFactory.createEmptyBorder(2, 2, 2, 2));
JTextArea tarea = new JTextArea(10, 10);
tarea.setBackground(Color.DARK_GRAY.darker());
tarea.setForeground(Color.WHITE);
tarea.setCaretColor(Color.WHITE);
tarea.setLineWrap(true);
JScrollPane scrollPane = new JScrollPane(tarea);
centerPanel.add(scrollPane, BorderLayout.CENTER);
JPanel footerPanel = new JPanel();
footerPanel.setLayout(new BorderLayout(5, 5));
footerPanel.setBorder(
BorderFactory.createEmptyBorder(2, 2, 2, 2));
JLabel cmdLabel = new JLabel("Cmd : ");
JTextField tfield = new JTextField(10);
JPanel buttonPanel = new JPanel();
buttonPanel.setBorder(
BorderFactory.createEmptyBorder(2, 2, 2, 2));
JButton sendButton = new JButton("SEND");
footerPanel.add(cmdLabel, BorderLayout.LINE_START);
footerPanel.add(tfield, BorderLayout.CENTER);
buttonPanel.add(sendButton);
footerPanel.add(buttonPanel, BorderLayout.LINE_END);
frame.getContentPane().add(centerPanel, BorderLayout.CENTER);
frame.getContentPane().add(footerPanel, BorderLayout.PAGE_END);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new LayoutExample().createAndDisplayGUI();
}
});
}
}
OUTPUT :
Base problem here is what I consider a bug in JTextField's max layout hint: it's unbounded in both horizontal and vertical dimension. The latter is pure nonsense for a component designed for showing a single line of text. To fix, subclass and let it return its pref for the height, like:
JTextField cmdInput = new JTextField() {
#Override
public Dimension getMaximumSize() {
Dimension max = super.getMaximumSize();
max.height = getPreferredSize().height;
return max;
}
};
As BoxLayout respects maxSize, the excess height now will be given to the top box only.
On the long run, consider switching to a third party manager which allows fine-tuning in a all-in-one-panel approach. Yeah, here comes my current favourite: MigLayout. Compare the following lines to all the nesting and border tricks above and have fun :-)
MigLayout layout = new MigLayout("wrap 3, debug",
"[][grow, fill][]", // 3 columns, middle column filled and allows growing
"[grow, fill][]"); // two rows, first filled and allows growing
JComponent content = new JPanel(layout);
// the scrollPane in the first row spanning all columns
// and growing in both directions
content.add(new JScrollPane(new JTextArea(20, 20)), "span, grow");
// auto-wrapped to first column in second row
content.add(new JLabel("Cmd:"));
content.add(new JTextField());
content.add(new JButton("Submit"));