I am trying to add button in my GUI using Gridbagconstraints in LayoutManager in Java. The location of the button is always in the center, irrespective of the coordinates.
package StudentInfo;
import javax.swing.*;
import java.awt.*;
public class Gui {
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
frame.add(panel);
panel.setLayout(new GridBagLayout());
frame.setSize(600,600);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
GridBagConstraints gbc = new GridBagConstraints();
JButton b = new JButton("Hello");
gbc.gridx=1;
gbc.gridy=1;
panel.add(b,gbc);
JButton v = new JButton("exit");
gbc.gridx=1;
gbc.gridx=0;
panel.add(v,gbc);
}
}
Output
Question
How to define co-ordinates of the buttons and place them at desired location?
You need to set weightx and weighty for the GridBagConstraints object.
Unless you specify at least one non-zero value for weightx or weighty, all the components clump together in the center of their container. This is because when the weight is 0.0 (the default), the GridBagLayout puts any extra space between its grid of cells and the edges of the container.
How to Use GridBagLayout
I recommend you read through this tutorial as well as the ones on the other swing layout managers if you want to continue working with GUIs in Java as they require a good deal of proficiency to use properly.
Related
I'm using the NetBeans GUI builder to handle my layout (I'm terrible with LayoutManagers) and am trying to place a simple JLabel so that it is always centered (horizontally) inside its parent JPanel. Ideally, this would maintain true even if the JPanel was resized, but if that's a crazy amount of coding than it is sufficient to just be centered when the JPanel is first created.
I'm bad enough trying to handle layouts myself, but since the NetBeans GUI Builder autogenerates immutable code, it's been impossible for me to figure out how to do this centering, and I haven't been able to find anything online to help me.
Thanks to anybody who can steer me in the right direction!
Here are four ways to center a component:
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
class CenterComponent {
public static JLabel getLabel(String text) {
return getLabel(text, SwingConstants.LEFT);
}
public static JLabel getLabel(String text, int alignment) {
JLabel l = new JLabel(text, alignment);
l.setBorder(new LineBorder(Color.RED, 2));
return l;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JPanel p = new JPanel(new GridLayout(2,2,4,4));
p.setBackground(Color.black);
p.setBorder(new EmptyBorder(4,4,4,4));
JPanel border = new JPanel(new BorderLayout());
border.add(getLabel(
"Border", SwingConstants.CENTER), BorderLayout.CENTER);
p.add(border);
JPanel gridbag = new JPanel(new GridBagLayout());
gridbag.add(getLabel("GridBag"));
p.add(gridbag);
JPanel grid = new JPanel(new GridLayout());
grid.add(getLabel("Grid", SwingConstants.CENTER));
p.add(grid);
// from #0verbose
JPanel box = new JPanel();
box.setLayout(new BoxLayout(box, BoxLayout.X_AXIS ));
box.add(Box.createHorizontalGlue());
box.add(getLabel("Box"));
box.add(Box.createHorizontalGlue());
p.add(box);
JFrame f = new JFrame("Streeeetch me..");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(p);
f.pack();
f.setLocationByPlatform(true);
f.setVisible(true);
}
});
}
}
By using Borderlayout, you can put any of JComponents to the CENTER area. For an example, see an answer to Stack Overflow question Get rid of the gap between JPanels. This should work.
Even with BoxLayout you can achieve that:
JPanel listPane = new JPanel();
listPane.setLayout(new BoxLayout(listPane, BoxLayout.X_AXIS ));
JLabel label = new JLabel();
listPane.add(Box.createHorizontalGlue());
listPane.add(label);
listPane.add(Box.createHorizontalGlue());
mKorbel's solution is perfect for your goal. Anyway I always like to suggest BoxLayout because it's very flexible.
Mara: "thanks for your response, however the NetBeans GUI Build uses GroupLayout and this is not overridable."
Not true! Right click anywhere inside JFrame (or any other GUI container) in NetBeans GUI builder and select "Set Layout". By default is selected "Free Design", which is Group layout, but you can select any other layout including Border layout as advised by mKorbel.
There's many ways to do this, depending on the layout manager(s) you use. I suggest you read the Laying Out Components Within a Container tutorial.
I believe the following will work, regardless of layout manager:
JLabel.setHorizontalAlignment(SwingConstants.CENTER)
I have a JFrame and three JPanels. On the frame I used BorderLayout. At the CENTER of the frame I have put outerPanel. On my outerPanel I have used MigLayout. The two other panels are added on to the outerPanel. These two panels are of equal size and their widths add up to the width of the outerPanel - I wanted the outerPanel to be divided into two halves. Below is the code for this:
public class ControlPanel extends JFrame {
// components
public JPanel outerPanel;
public JPanel innerPanel1;
public JPanel innerPanel2;
public ControlPanel() {
this.createUI();
}
public void createUI() {
// form properties
this.setSize(new java.awt.Dimension(300, 300));
this.setVisible(true);
this.setLayout(new java.awt.BorderLayout());
this.outerPanel = new JPanel();
this.outerPanel.setPreferredSize(new java.awt.Dimension(260, 250));
this.outerPanel.setLayout(new net.miginfocom.swing.MigLayout());
this.outerPanel.setBorder(BorderFactory.createEtchedBorder());
this.add(new javax.swing.JLabel("North"), BorderLayout.NORTH);
this.add(this.outerPanel, BorderLayout.CENTER);
this.innerPanel1 = new JPanel();
this.innerPanel1.setPreferredSize(new java.awt.Dimension(130, 150));
this.innerPanel1.setLayout(new net.miginfocom.swing.MigLayout());
this.innerPanel1.setBorder(BorderFactory.createTitledBorder("Panel1"));
this.innerPanel2 = new JPanel();
this.innerPanel2.setPreferredSize(new java.awt.Dimension(130, 150));
this.innerPanel2.setLayout(new net.miginfocom.swing.MigLayout());
this.innerPanel2.setBorder(BorderFactory.createTitledBorder("Panel2"));
this.outerPanel.add(this.innerPanel1);
this.outerPanel.add(this.innerPanel2);
this.pack();
}
public static void main(String[] args) {
ControlPanel cp = new ControlPanel();
}
}
Problem: When I run my program, the GUI that appears before I resize the window is fine; but when I resize the window -enlarging it, innerPane1 and innerPanel2 remains of the same size without resizing to occupy the space available.
Question: How do we make the two panels , innerPannel1 and innerPanel2, resize at the same time with the window so that they can share equally the available space? Any particular Layout Manager that can be used to divide a panel into two equal halves that can resize at the same time with the window?
Images Showing the output.
Before resizing - the GUI looks well and the panels have correct size.
After resizing -the GUI is distorted and the panels doesn't change size.
I suggest you use new GridLayout(1, 2). This will split the panel in 1 row and 2 (equally sized) columns.
So, simply changing
this.outerPanel = new JPanel();
to
this.outerPanel = new JPanel(new GridLayout(1, 2));
should do.
I am currently trying to take the typed text in the textField 'itemName' and have it print out on the text area 'printArea.' When I have both printArea and itemName on the same JPanel (p1) it works just fine. When printArea is set to a separate JPanel (itemName on p1 and printArea on p2), nothing prints out. Two JPanels are used to make the GUI appear as it was assigned. The area i Believe to be the issue is where I added JPanel 'p1' to JPanel 'p2'.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class MovieGUI extends JFrame{
JButton submit = new JButton("Submit");
JTextField itemName = new JTextField();
JTextField itemPrice = new JTextField();
JTextField itemQuantity = new JTextField();
JTextArea printArea = new JTextArea(400,400);
public MovieGUI(){
JPanel p1 = new JPanel();
p1.setLayout(new GridLayout(6, 2));
p1.add(new JLabel("Item Name"));
p1.add(itemName); //p1.add(new JTextField(8));
p1.add(new JLabel("Item Price"));
p1.add(itemPrice); // p1.add(new JTextField(8));
p1.add(new JLabel("Quantity"));
p1.add(itemQuantity); //p1.add(new JTextField(8));
p1.add(new JLabel("submit"));
p1.add(submit);
//Something is not working...
JPanel p2 = new JPanel(new BorderLayout());
p2.setLayout(new BorderLayout());
p2.add(p1, BorderLayout.NORTH);
p2.add(printArea, BorderLayout.SOUTH);
//add(p1);
add(p2);
event e = new event();
submit.addActionListener(e);
}
public class event implements ActionListener{
public void actionPerformed(ActionEvent e){
String text = itemName.getText();
printArea.setText(text); //printArea.setText("BUTTON");
}
}
public static void main(String[] args){
MovieGUI frame = new MovieGUI();
frame.setTitle("Submission");
frame.setSize(800, 500);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Your JPanel p2 does not contain nothing on CENTER alignment, so printArea doesn't view on SOUTH alignment. To see the inputItem text on printArea change from
p2.add(printArea, BorderLayout.SOUTH);
to
p2.add(printArea, BorderLayout.CENTER);
Your text is being printed in printArea, but the first line (and more) of the printArea is hidden behind p1. This is because the south location with printArea is filling the entirety of p2, but it's z-index means it is behind p1. You can see this if you do:
p2.add(printArea, BorderLayout.SOUTH);
printArea.setBackground(Color.BLUE);
p2.setComponentZOrder(printArea, 0); // now the blue printArea hides the form elements in p1
To fix this: change printArea to CENTER instead of SOUTH.
Why?
It helps to understand how BorderLayout works to understand why. It is not splitting up the areas by percentage but it is used to arrange components around a centre panel. The order of the layout is:
North / South components will use their preferred height, and then the width of the component they're in.
I'll ignore East/West in here as you aren't using them.
Centre will use the remaining space after the N/S/E/W components have been sized
Your printArea's preferred height was "huge" (technical term!), so it was trying to use that. Once in a centre panel it is told to use the remaining space only: as p1 has a preferred height that is smaller than the p2 height, the centre panel gets the remaining height and you can still see the printArea. You can also see this effect if you reverse the addition order when using NORTH/SOUTH; you would then only see the printArea, not the p1 form.
If you take a look at the source of BorderLayout in the JDK, you can see the layoutContainer method where this all takes place.
Is it possible to have some extra space around the edges of a JFrame that uses AbsoluteLayout? When I have a button as the downwardsmost component on the JFrame, it gets positioned right up against the bottom edge of the JFrame window, and it looks bad. I would like to know if there's a way to add a little extra space between components and the edge of the JFrame while using AbsoluteLayout.
Suggestions:
When you add a component to a JFrame, you're actually adding it to the JFrame's contentPane. To give the contentPane a "buffer" border, consider giving it an EmptyBorder(...) with the parameters being int constants for the amount of border desired around the component.
Avoid using "absolute" layouts for anything, and especially for placing components at easy to place locations for the layout managers, such as at the bottom of the GUI.
For example, note in the GUI created in the code below how the center and bottom JPanel's don't go out to the edge of the GUI because of the empty border:
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.*;
public class ButtonAtBottom {
private static void createAndShowGui() {
JPanel bottomPanel = new JPanel();
bottomPanel.add(new JButton("Bottom Button"));
bottomPanel.setBorder(BorderFactory.createTitledBorder("Bottom Panel"));
JPanel centerPanel = new JPanel();
centerPanel.setBorder(BorderFactory.createTitledBorder("Center Panel"));
JPanel mainPanel = new JPanel(new BorderLayout());
mainPanel.add(centerPanel, BorderLayout.CENTER);
mainPanel.add(bottomPanel, BorderLayout.PAGE_END);
// **** here I add the border to the mainPanel which I'll
// make into the contentPane
int eb = 25;
mainPanel.setBorder(BorderFactory.createEmptyBorder(eb, eb, eb, eb));
// don't set the preferredSize per Kleopatra, but am doing it
// here simply to make code shorter for this sscce
mainPanel.setPreferredSize(new Dimension(500, 400));
JFrame frame = new JFrame("ButtonAtBottom");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
You can use Box.createRigidArea(dimensions) to create an empty space that you can add below the button.
Set an empty border on your content panel where SIZE is the amount of padding you want.
JFrame frame = new JFrame();
JPanel panel = new JPanel(null);
panel.setBorder(BorderFactory.createEmptyBorder(SIZE,SIZE,SIZE,SIZE);
frame.setContentPane(panel);
//The rest
The arguments are for top, left, bottom and right padding so if you want different paddings on each edge, you can set it accordingly.
so i have a problem i cant solve i want my GUI app to be split between 3 JPanels (left, center, right). I want left panel and right panel to be of fixed size and center to be fluid. Meaning side panels expand only vertically as JFrame is expanded and center panel expands bot horizontally and vertically.
I have set minimal size for all panels to be height of 600 but they just stay in the minimal size and dont expand as JForm increases i dont know how to set bounds to JFrame borders so they expand whit it.
package ppe.view;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import net.miginfocom.swing.MigLayout;
public class UI_View extends JFrame
{
private JList browse = new JList();
private JScrollPane rightX = new JScrollPane();
private JButton btn1 = new JButton("Button 1");
private JButton btn2 = new JButton("Button 2");
private JButton btn3 = new JButton("Button 3");
private JButton btn4 = new JButton("Button 4");
public UI_View()
{
this.setTitle("Prototype MVC Arhitecture");
this.setMinimumSize(new Dimension(800, 600));
this.setExtendedState(this.MAXIMIZED_BOTH);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(new MigLayout());
JPanel content = new JPanel(new MigLayout());
content.setBackground(Color.black);
JPanel right = new JPanel(new MigLayout());
JPanel center = new JPanel(new MigLayout());
JPanel left = new JPanel(new MigLayout());
right.setBackground(Color.red);
right.setMinimumSize(new Dimension(200, 600));
right.setMaximumSize(new Dimension(200, 37500));
center.setBackground(Color.green);
center.setMinimumSize(new Dimension(400, 600));
left.setBackground(Color.blue);
left.setMinimumSize(new Dimension(200, 600));
left.setMaximumSize(new Dimension(200, 37500));
content.add(left);
content.add(center);
content.add(right);
this.setContentPane(content);
}
public static void main(String[] args)
{
new UI_View().setVisible(true);
}
}
I have tryed bounding them to another content panel and adding that panel as ContentPane to JFrame that automatically bounds it to JFrame border but the thing is still pretty much fixed.
If you're using MiGLayout why don't you configure the constraints when adding the components?
This, for example, might help (although I'm a MiGLayout beginner, too):
content.add(left, "growy");
content.add(center, "grow"); //the same as growx, growy
content.add(right, "growy");
In some cases I needed to also add a pushx but I'm not sure when this is needed. Please refer to the documentation for further information.
Edit: it seems like you always have to add push for components that should cause the column/row to grow. Otherwise grow alone would make the components as big as the column/row they are in which in turn is defined by the largest component in that column/row. If there is more space available columns/rows won't grow to fill it without the push keyword.
From the documentation:
Components will never "push" the column/row's size to be larger using the grow keyword.