First post, and tried to research this as much as possible but finally gave up and decided to ask.
I am building a recipe book program, and on one page it has the list of recipes. When you select a recipe it will appear on the left side as labels. The issue is on my page I have two JPanels. One hosts the list of recipes, the other is labels for displaying the information. On the side that has the labels I cant get them to move, or alter or anything inside the JPanel.
I feel this has a simple solution but I am too inexperienced to see. Anyway thanks for the help in advance.
////Form Panel Class
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class FormPanel extends JPanel {
private JScrollPane pane;
private JPanel pane2;
// viewing of information
private JLabel nameLabel1;
private JLabel nameLabel2;
private JLabel nameLabel3;
public FormPanel() {
nameLabel1 = new JLabel("Label1");
nameLabel2 = new JLabel("Recipe Name: ");
nameLabel3 = new JLabel("Tag Lines: ");
pane = new JScrollPane();
pane2 = new JPanel();
layoutComponents();
pane.setPreferredSize(new Dimension(200, 450));
pane2.setBorder(BorderFactory.createTitledBorder("Recipes"));
pane2.setPreferredSize(new Dimension(375, 450));
}
public void layoutComponents() {
setLayout(new GridBagLayout());
GridBagConstraints gc = new GridBagConstraints();
///////////////////////////////////////
// First Row
gc.gridy = 0;
gc.weightx = 1;
gc.weighty = 1;
gc.gridx = 1;
gc.anchor = GridBagConstraints.FIRST_LINE_START;
add(pane2, gc);
////////////////////////////////////////////
///////////////////////////////////////
// First Row
gc.gridy = 0;
gc.weightx = 2;
gc.weighty = 1;
gc.gridx = 1;
gc.anchor = GridBagConstraints.FIRST_LINE_END;
gc.insets = new Insets(5, 5, 5, 5);
add(pane, gc);
////////////////////////////////////////////
GridBagConstraints gc2 = new GridBagConstraints();
//
gc2.gridy = 0;
gc2.weightx = 1;
gc2.weighty = 1;
gc2.gridx = 0;
gc2.fill = GridBagConstraints.PAGE_START;
pane2.add(nameLabel2, gc2);
////////////////////////////////////////////
gc2.gridy = 1;
gc2.weightx = 1;
gc2.weighty = 1;
gc2.gridx = 0;
gc2.fill = GridBagConstraints.CENTER;
pane2.add(nameLabel3, gc2);
////////////////////////////////////////////
gc2.gridy = 2;
gc2.weightx = 1;
gc2.weighty = 1;
gc2.gridx = 0;
gc2.fill = GridBagConstraints.SOUTH;
pane2.add(nameLabel1, gc2);
}
}
//Mainframe Class
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JTabbedPane;
public class Mainframe extends JFrame {
private FormPanel formPanel;
private JTabbedPane tabPane;
public Mainframe() {
super("My Digital Cookbook");
setLayout(new BorderLayout());
formPanel = new FormPanel();
tabPane = new JTabbedPane();
add(tabPane, BorderLayout.PAGE_START);
tabPane.addTab("New Recipe", formPanel);
setMinimumSize(new Dimension(500, 600));
setSize(600, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
}
//Application Class
import javax.swing.SwingUtilities;
public class Application {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run(){
System.out.println(SwingUtilities.isEventDispatchThread());
new Mainframe();
}
});
}
}
The lower three labels might have wonkey weights and what not just due to trying to get them to move but they all just stay in a straight line near the top of the Jpanel.
Additionally I don't think I needed to re-declare my gridbagconstraints but I decided to try for debugging attempts.
**Update -I now have posted a much simpler version of my program with the error still existing. I apologize that I don't have it smaller due to lack of flexible skills.
Related
I try to make a simple app in SWING: using BorderLayout layout on the JFrame, i put on SOUTH an executing button, on WEST a panel that contains a combobox and on EAST a panel that contains 2 JTextAreas. The problem is, both JTextArea are damn small. Any help and explanation will be welcomed.
This is the code for the panel with the 2 text areas
package cipher;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.border.Border;
class TextPanel extends JPanel {
private JTextArea inputArea, outputArea;
public TextPanel() {
initSize();
initTextArea();
initBorder();
initLayout();
packing();
}
private void packing() {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 1;
gbc.weighty = 1;
add(inputArea,gbc);
gbc.gridx = 0;
gbc.gridy = 1;
gbc.weightx = 1;
gbc.weighty = 1;
add(outputArea,gbc);
}
private void initBorder() {
Border outer = BorderFactory.createEmptyBorder(5, 5, 5, 5);
Border inner = BorderFactory.createTitledBorder("Text");
setBorder(BorderFactory.createCompoundBorder(outer,inner));
}
private void initLayout() {
setLayout(new GridBagLayout());
}
private void initTextArea() {
inputArea = new JTextArea();
inputArea.setPreferredSize(new Dimension(385,400));
outputArea = new JTextArea();
outputArea.setPreferredSize(new Dimension(385,400));
}
private void initSize() {
Dimension size = getPreferredSize();
size.width = 390;
setPreferredSize(size);
}
}
I've tried using setSize(x,y) but without success. I've tried using JTextArea(rows,columns) but without success. I've used even setPreferredSize with a Dimension but no succeed.
The probable cause of your issue is the container area is smaller than the preferred size of the text area, GridBagLayout will then default to the minimum size instead.
This is a good example of why you should avoid setting these properties directly and instead make use of the layout manager and the components properties.
To start with, make use of the JTextArea's column and rows properties. This will make a better "guess" at the amount of space it needs to display text to fit within these confines.
Second, use GridBagConstraints#fill to override GridBagLayout and force it to make use of the available space
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TextPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TextPanel extends JPanel {
private JTextArea inputArea, outputArea;
public TextPanel() {
initTextArea();
initBorder();
initLayout();
packing();
}
private void packing() {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.fill = GridBagConstraints.BOTH;
add(inputArea, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.fill = GridBagConstraints.BOTH;
add(outputArea, gbc);
}
private void initBorder() {
Border outer = BorderFactory.createEmptyBorder(5, 5, 5, 5);
Border inner = BorderFactory.createTitledBorder("Text");
setBorder(BorderFactory.createCompoundBorder(outer, inner));
}
private void initLayout() {
setLayout(new GridBagLayout());
}
private void initTextArea() {
// The borders are just here so you can see the different text areas
inputArea = new JTextArea(10, 20);
inputArea.setBorder(new LineBorder(Color.BLACK));
outputArea = new JTextArea(10, 20);
outputArea.setBorder(new LineBorder(Color.BLACK));
}
}
}
I'd also change...
inputArea = new JTextArea(10, 20);
inputArea.setBorder(new LineBorder(Color.BLACK));
outputArea = new JTextArea(10, 20);
outputArea.setBorder(new LineBorder(Color.BLACK));
and make use of JScrollPanes instead of LineBorder
I'm trying to display a series of buttons in a JScrollpane. Reading around, I managed to exit with this code, but nothing is displayed. I do not understand a possible mistake. Thank you for help
As suggested I made some changes, I edited but not works
EDITED
or I'm stupid, or here is some other problem. Here is my complete code with the output image
public class Main extends javax.swing.JFrame {
private final JPanel gridPanel;
public Main() {
initComponents();
// EXISTING PANEL
gridPanel = new JPanel();
JScrollPane scrollPane = new JScrollPane(gridPanel);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
JPanel borderLayoutPanel = new JPanel(new BorderLayout());
borderLayoutPanel.add(scrollPane, BorderLayout.CENTER);
this.Avvio();
}
private void Avvio() {
JPanel pane = new JPanel(new GridBagLayout());
pane.setBorder(BorderFactory.createLineBorder(Color.BLUE));
pane.setLayout(new GridBagLayout());
for (int i = 0; i < 10; i++) {
JButton button;
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.PAGE_START;
button = new JButton("Button 1");
c.weightx = 0.5;
c.gridx = 0;
c.gridy = i;
pane.add(button, c);
button = new JButton("Button 2");
c.gridx = 1;
c.gridy = i;
pane.add(button, c);
button = new JButton("Button 3");
c.gridx = 2;
c.gridy = i;
pane.add(button, c);
}
gridPanel.add(pane);
gridPanel.revalidate();
gridPanel.repaint();
}
}
Alright, from your comments in another answer:
No problem for compile , simply the Jpanel is empty. The buttons does not appear.
After calling this.Avvio(); you must call:
this.add(scrollPane);
this.pack();
This will produce the following outputs (before and after resizing it):
But there's still no JScrollPanel
This at least solves the first problem, however you have more errors in your code, some of which have already been commented in other answers:
You're extending JFrame, this isn't needed as you can create a JFrame instance / object and use it later. You're never changing the JFrame's behavior and that's why it's not needed to extend it. See Extends JFrame vs. creating it inside the program for more information about this.
You're not calling pack() nor setSize(...) this creates a tiny window, which you need to manually resize. Call pack() recommended before making your JFrame visible. (As suggested at the beginning of this answer).
You're calling .invokeLater() method twice. You need to call it just once, I prefer this way:
SwingUtilities.invokeLater(() -> new Main()); //Note there is no call to .setVisible(true); as per point #1. It should go later in the program like: frame.setVisible(true);
You're calling gridPanel.revalidate(); and gridPanel.repaint() while it doesn't affect your program, it's not needed as your GUI is still not visible, and thus those calls have no effect on your program, you can safely remove them.
You're creating a new GridBagConstraints object on each iteration of the for loop, you can just change its properties inside it and declaring it outside the for loop, which will make your program better.
After following the above recommendations, you can end up with a code like this one:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class Main {
private final JPanel gridPanel;
private JFrame frame;
public Main() {
// EXISTING PANEL
gridPanel = new JPanel();
JScrollPane scrollPane = new JScrollPane(gridPanel);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
JPanel borderLayoutPanel = new JPanel(new BorderLayout());
borderLayoutPanel.add(scrollPane, BorderLayout.CENTER);
this.Avvio();
frame.add(scrollPane);
frame.pack();
frame.setVisible(true);
}
private void Avvio() {
JPanel pane = new JPanel(new GridBagLayout());
pane.setBorder(BorderFactory.createLineBorder(Color.BLUE));
pane.setLayout(new GridBagLayout());
for (int i = 0; i < 10; i++) {
JButton button;
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.PAGE_START;
button = new JButton("Button 1");
c.weightx = 0.5;
c.gridx = 0;
c.gridy = i;
pane.add(button, c);
button = new JButton("Button 2");
c.gridx = 1;
c.gridy = i;
pane.add(button, c);
button = new JButton("Button 3");
c.gridx = 2;
c.gridy = i;
pane.add(button, c);
}
gridPanel.add(pane);
}
public static void main(String args[]) {
/* Create and display the form */
SwingUtilities.invokeLater(() -> {
new Main();
});
}
}
Which still produces this output:
BUT... We still can improve it a little more!
We may have two nested for loops, for the GridBagConstraints properties as well as the generation of the buttons:
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
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 ScrollablePaneWithButtons {
private static final int ROWS = 10;
private static final int COLS = 3;
private JFrame frame;
private JPanel pane;
private JButton[][] buttons;
private GridBagConstraints gbc;
private JScrollPane scroll;
private JButton[] menuButtons;
private JPanel menuPane;
public static void main(String[] args) {
SwingUtilities.invokeLater(new ScrollablePaneWithButtons()::createAndShowGui);
}
private void createAndShowGui() {
frame = new JFrame(this.getClass().getSimpleName());
pane = new JPanel();
pane.setLayout(new GridBagLayout());
menuPane = new JPanel();
menuPane.setLayout(new GridLayout(1, 3));
buttons = new JButton[ROWS][COLS];
menuButtons = new JButton[] {new JButton("Edit"), new JButton("Delete"), new JButton("Sort Fields")};
gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.anchor = GridBagConstraints.PAGE_START;
gbc.weightx = 0.5;
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
buttons[i][j] = new JButton("Button " + (j + 1));
gbc.gridx = j;
gbc.gridy = i;
pane.add(buttons[i][j], gbc);
}
}
scroll = new JScrollPane(pane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
for (JButton b : menuButtons) {
menuPane.add(b);
}
frame.add(scroll);
frame.add(menuPane, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
And this example is (in my opinion) easier to read and follow up. And this is the output the above code is generating:
You can still choose which code to use, either doing the modifications at the first part of this answer, the second one following the recommendations above or the last one which is shorter.
Problems noted:
Avvio - the pane layout was reset during each loop. Set it once before the loop.
Avvio - the pane was added to the grid pane in each loop. Add it once after the loop.
Avvio - the constraints place the buttons in the same grid locations. With the previous two issues fixed, only the last three buttons placed appear.
I'm assuming you want three buttons in a row, so I changed the loop to use the counter as a row counter. The code below will create ten rows of three buttons.
What appears:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.WindowConstants;
public class Main extends javax.swing.JFrame {
private JPanel gridPanel;
public Main() {
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.setSize(600,400);
//EXISTING PANEL
gridPanel = new JPanel();
JScrollPane scrollPane = new JScrollPane(gridPanel);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
JPanel borderLayoutPanel = new JPanel(new BorderLayout());
borderLayoutPanel.add(scrollPane, BorderLayout.CENTER);
this.Avvio();
this.add(borderLayoutPanel, BorderLayout.CENTER);
this.setVisible(true);
}
private void Avvio() {
JPanel pane = new JPanel(new GridBagLayout());
pane.setBorder(BorderFactory.createLineBorder(Color.BLUE));
pane.setLayout(new GridBagLayout());
for (int i = 0; i < 10; i++) {
JButton button;
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.PAGE_START;
button = new JButton("Button 1");
c.weightx = 0.5;
c.gridx = 0;
c.gridy = i;
pane.add(button, c);
button = new JButton("Button 2");
c.gridx = 1;
c.gridy = i;
pane.add(button, c);
button = new JButton("Button 3");
c.gridx = 2;
c.gridy = i;
pane.add(button, c);
}
gridPanel.add(pane);
gridPanel.revalidate();
gridPanel.repaint();
}
public static void main(String args[]) {
new Main();
}
}
There are several things to do to make it work:
Add a main method
This main method is the entry point. This makes sure the swing-code runs in the AWT-thread. This is what the SwingUtilities.invokeLater is for
Instantiate, pack and display the frame. The size setting is only for experimenting with the scrollpane
Declare the gridPanel as an instance variable
wrap the gridPanel with the scrollPane
Optionally, wrap the scrollPane with the borderLayoutPanel
Invoke the Avvio method because this is the one that adds the buttons
Add the outmost element to the frame
Here is the fixed code:
public class MyFrame extends javax.swing.JFrame {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
MyFrame frame = new MyFrame();
frame.pack();
frame.setSize(600, 300);
frame.setVisible(true);
});
}
private JPanel gridPanel;
public MyFrame() {
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
gridPanel = new JPanel(new GridLayout(0, 1));
JScrollPane scrollPane = new JScrollPane(gridPanel);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
JPanel borderLayoutPanel = new JPanel(new BorderLayout());
borderLayoutPanel.add(scrollPane, BorderLayout.CENTER);
this.Avvio();
this.add(borderLayoutPanel, BorderLayout.CENTER);
}
private void Avvio() {...}
}
I have simplified the program and removed all the mistakes
and bad practices. (Missing package, unnecessary panels, calling invokeLater() twice and others.)
Here is a working example:
package com.zetcode;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class JavaScrollPaneEx extends JFrame {
public JavaScrollPaneEx() {
initUI();
}
private void initUI() {
JPanel panel = new JPanel(new BorderLayout());
JPanel buttonPanel = createButtonPanel();
JScrollPane scrollPane = new JScrollPane(buttonPanel);
panel.add(scrollPane, BorderLayout.CENTER);
add(panel);
setTitle("Buttons in JScrollBar");
setSize(350, 250);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.PAGE_START;
c.insets = new Insets(5, 5, 5, 5);
for (int i = 0, j = 0; i < 5; i++) {
JButton btn = new JButton("Button " + (j + 1));
c.weightx = 0.5;
c.gridx = i;
c.gridy = 0;
panel.add(btn, c);
btn = new JButton("Button " + (j + 2));
c.gridx = i;
c.gridy = 1;
panel.add(btn, c);
btn = new JButton("Button " + (j + 3));
c.gridx = i;
c.gridy = 2;
panel.add(btn, c);
j += 3;
}
return panel;
}
public static void main(String args[]) {
EventQueue.invokeLater(() -> {
JavaScrollPaneEx ex = new JavaScrollPaneEx();
ex.setVisible(true);
});
}
}
And this is the screenshot.
And since I consider GridBagLayout to be a very bad
layout manager, I have created a similar example with MigLayout
manager.
We need the following Maven dependency for this example:
<dependency>
<groupId>com.miglayout</groupId>
<artifactId>miglayout-swing</artifactId>
<version>5.0</version>
</dependency>
The source:
package com.zetcode;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JButton;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import net.miginfocom.swing.MigLayout;
public class JavaScrollPaneEx2 extends JFrame {
public JavaScrollPaneEx2() {
initUI();
}
private void initUI() {
JPanel panel = new JPanel(new BorderLayout());
JPanel buttonPanel = createButtonPanel();
JScrollPane scrollPane = new JScrollPane(buttonPanel);
panel.add(scrollPane, BorderLayout.CENTER);
add(panel);
setTitle("Buttons in JScrollBar");
setSize(350, 250);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel(new MigLayout());
for (int i = 0, j = 0; i < 5; i++) {
JButton btn1 = new JButton("Button " + (j + 1));
JButton btn2 = new JButton("Button " + (j + 2));
JButton btn3 = new JButton("Button " + (j + 3));
JButton btn4 = new JButton("Button " + (j + 4));
JButton btn5 = new JButton("Button " + (j + 5));
panel.add(btn1, "sgx");
panel.add(btn2, "sgx");
panel.add(btn3, "sgx");
panel.add(btn4, "sgx");
panel.add(btn5, "sgx, wrap");
j += 5;
}
return panel;
}
public static void main(String args[]) {
EventQueue.invokeLater(() -> {
JavaScrollPaneEx2 ex = new JavaScrollPaneEx2();
ex.setVisible(true);
});
}
}
I'm working on a small GUI project that builds a book manger to mange a book. In my layout, I want a textArea to display information about my book, a text JLabel underneath my textArea and a JTextArea for me to input information same column of JLabel and 1 row next to Label. However when I run my program, textArea and Label is completely cover over my textArea.
How can I fix this problem. Thanks!!
import java.awt.*;
import javax.swing.*;
public class Design extends JFrame {
JButton button1;
JTextArea outputArea;
JLabel stockLabel, bookPriceLabel;
JTextField stockTextField, priceTextField;
JPanel panel;
GridBagConstraints gc;
public Design(){
super("Book Info");
gc = new GridBagConstraints ();
panel = new JPanel();
outputArea = new JTextArea(20, 50);
stockLabel = new JLabel ("Books In Stock");
bookPriceLabel = new JLabel("Book Price");
stockTextField = new JTextField(10);
button1 = new JButton ("button1");
panel.setLayout(new GridBagLayout());
panel.setSize(600, 600);
gc.anchor = GridBagConstraints.NORTHWEST;
gc.weightx = 1;
gc.weighty = 1;
panel.add(outputArea, gc);
gc.gridx = 2;
gc.gridy = 2;
panel.add(stockLabel, gc);
gc.gridx = 3;
gc.gridy = 2;
panel.add(stockTextField, gc);
this.getContentPane().add(panel);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(600,600);
setVisible(true);
setLocationRelativeTo(null);
}
public static void main (String args[]){
Design frame = new Design();
}
}
You could apply a gridWidth constraint to the JTextArea which would allow it to span multiple columns.
Remember, GridBagLayout is still based around the concept of a grid (rows and columns), but which provides a lot of flexibility to customise how components fill and span through out that grid
Maybe something like...
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
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 Design extends JFrame {
JButton button1;
JTextArea outputArea;
JLabel stockLabel, bookPriceLabel;
JTextField stockTextField, priceTextField;
JPanel panel;
GridBagConstraints gc;
public Design() {
super("Book Info");
gc = new GridBagConstraints();
panel = new JPanel();
outputArea = new JTextArea(20, 50);
stockLabel = new JLabel("Books In Stock");
bookPriceLabel = new JLabel("Book Price");
stockTextField = new JTextField(10);
button1 = new JButton("button1");
panel.setLayout(new GridBagLayout());
gc.anchor = GridBagConstraints.NORTHWEST;
gc.gridx = 0;
gc.gridy = 0;
gc.weightx = 1;
gc.weighty = 1;
gc.gridwidth = GridBagConstraints.REMAINDER;
panel.add(new JScrollPane(outputArea), gc);
gc.weightx = 0;
gc.weighty = 0;
gc.anchor = GridBagConstraints.WEST;
gc.gridwidth = 1;
gc.gridx = 0;
gc.gridy = 2;
panel.add(stockLabel, gc);
gc.gridx++;
gc.gridy = 2;
panel.add(stockTextField, gc);
this.getContentPane().add(panel);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
setLocationRelativeTo(null);
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
Design frame = new Design();
}
});
}
}
See How to Use GridBagLayout for more details
Some general feedback:
There's no point in calling setSize on a component which will be added to a container which using a layout manager, the action will simply be ignored and the layout manager will call setSize with what it wants to use
JTextArea really should be contained within a JScrollPane, you'll get some weird results if you don't (it will want to grow as the text occupies more space)
Prefer JFrame#pack over JFrame#setSize, this will take into account the frame borders, wrapping the frame around the contents
You really should avoid extending directly from top level containers like JFrame, apart from locking you into a single use case, you're really not adding any new functionality to the frame. Instead, start with something like a JPanel, build you core UI ontop of that and then, when you need to, add that to what ever container you want
Here is what I have:
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ScrollPaneConstants;
import javax.swing.border.LineBorder;
public class Main {
// Field members
static JPanel panel = new JPanel();
static Integer indexer = 1;
static List<JLabel> listOfLabels = new ArrayList<JLabel>();
static List<JTextField> listOfTextFields = new ArrayList<JTextField>();
static JScrollPane scrollPane;
public static void main(String[] args) {
// Construct frame
JFrame frame = new JFrame();
frame.setLayout(new GridBagLayout());
//frame.setPreferredSize(new Dimension(990, 990));
frame.setTitle("My Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Frame constraints
//GridBagConstraints frameConstraints = new GridBagConstraints();
// Construct button
JButton addButton = new JButton("Add");
addButton.addActionListener(new ButtonListener());
// Add button to frame
//frameConstraints.gridx = 0;
//frameConstraints.gridy = 0;
//frame.add(addButton, frameConstraints);
frame.add(addButton);
// Construct panel
panel.setPreferredSize(new Dimension(1000, 1000));
panel.setLayout(new GridBagLayout());
panel.setBorder(LineBorder.createBlackLineBorder());
scrollPane = new JScrollPane(panel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.setPreferredSize(new Dimension(600, 600));
// Add panel to frame
//frameConstraints.gridx = 0;
//frameConstraints.gridy = 1;
//frameConstraints.weighty = 1;
//frame.add(panel, frameConstraints);
frame.add(scrollPane);
// Pack frame
frame.pack();
// Make frame visible
frame.setVisible(true);
}
static class ButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent arg0) {
// Clear panel
panel.removeAll();
// Create label and text field
//JTextField jTextField = new JTextField();
//jTextField.setSize(100, 200);
//listOfTextFields.add(jTextField);
listOfLabels.add(new JLabel("" + indexer));
// Create constraints
//GridBagConstraints textFieldConstraints = new GridBagConstraints();
GridBagConstraints labelConstraints = new GridBagConstraints();
// Add labels and text fields
for (int i = 0; i < indexer; i++) {
// Text field constraints
//textFieldConstraints.gridx = 1;
//textFieldConstraints.fill = GridBagConstraints.HORIZONTAL;
//textFieldConstraints.weightx = 0.5;
//textFieldConstraints.insets = new Insets(10, 10, 10, 10);
//textFieldConstraints.gridy = i;
// Label constraints
labelConstraints.gridx = 0;
labelConstraints.gridy = i;
labelConstraints.insets = new Insets(0, 0, 0, 0);
// Add them to panel
panel.add(listOfLabels.get(i), labelConstraints);
//panel.add(listOfTextFields.get(i), textFieldConstraints);
}
// Align components top-to-bottom
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = indexer;
c.weighty = 1;
c.ipady = 0;
panel.add(new JLabel(), c);
System.out.println("indexer is " + indexer);
// Increment indexer
indexer++;
panel.updateUI();
if(indexer ==2){
listOfLabels.set(0, new JLabel("Test"));
}
}
private int getWidth() {
// TODO Auto-generated method stub
return 0;
}
}
}
Here is the output:
What Am I doing wrong? I want the labels to be justified all the way to the left. I don't have any padding set to the left so I am confused.
FYI, I found this code on stackoverflow and my goal is to have labels that I can dynamically add and update, hence I commented out the textboxes.
Don't call setPreferredSize on the scroll pane, this isn't what you should setting, use GridBagConstraints weightx/y and fill properties.
Don't call updateUI, it doesn't do what you think it does, call revalidate instead, if you have to
The main reasons you're having problems is
You're call setPreferredSize on the panel. When adding components to a GridBagLayout, it will attempt to lay out components around the centre of the container
You've not specified a weightx or anchor property for the GridBagConstraints when adding the labels
I'm using GridBagLayout to place my GUI components by the following code, wanting the components lay one by one in a column, without any gaps :
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TestGUI extends JFrame{
public TestGUI(){
JPanel bigPanel = new JPanel(new GridBagLayout());
JPanel panel_a = new JPanel();
JButton btnA = new JButton("button a");
panel_a.add(btnA);
JPanel panel_b = new JPanel();
JButton btnB = new JButton("button b");
panel_b.add(btnB);
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
c.weighty = 1D;
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.NORTH;
bigPanel.add(panel_a, c);
c.gridx = 0;
c.gridy = 1;
c.fill = GridBagConstraints.HORIZONTAL;
bigPanel.add(panel_b, c);
this.add(bigPanel);
}
public static void main(String[] args) {
TestGUI gui = new TestGUI();
gui.setVisible(true);
gui.pack();
}
}
I wish the panels will be shown one by one in the column. but now i got this :
As i am going to add some more components in the bigPanel, and required some more customization to the layout, so i need to use GridBagLayout instead of other Layout.
You need to add an extra component so that it will fill the rest of the available space and push the two button-panels to the top. When you will add more components, you can of course remove that component.
Another option (without requiring an extra component) would have been to set weighty=1.0 for the panel_b and anchor=NORTH, but then you would have to change that when you add more components.
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestGUI extends JFrame {
public TestGUI() {
JPanel bigPanel = new JPanel(new GridBagLayout());
JPanel panel_a = new JPanel();
JButton btnA = new JButton("button a");
panel_a.add(btnA);
JPanel panel_b = new JPanel();
JButton btnB = new JButton("button b");
panel_b.add(btnB);
GridBagConstraints c = new GridBagConstraints();
c.gridwidth = GridBagConstraints.REMAINDER;
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1.0;
bigPanel.add(panel_a, c);
bigPanel.add(panel_b, c);
c.weighty = 1.0;
// Temporary panel to fill the rest of the bigPanel
bigPanel.add(new JPanel(), c);
this.add(bigPanel);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
TestGUI gui = new TestGUI();
gui.pack();
gui.setVisible(true);
}
});
}
}