GradBagLayout not distributing columns based on weight - java

This is what my GUI looks like now:
I want it to have the three columns to be equally distributed. To do this, I set each of the weights equal to 1/3. Obviously, it's not working.
Here is my code for creating the Frame:
public static JPanel createLayout(int rows) {
JPanel product = new JPanel(new GridBagLayout());
String[] lables = {"School ", "Advanced #", "Novice # "};
double weight = .3333333333333;
GridBagConstraints c = new GridBagConstraints();
c.insets = new Insets(3, 3, 3, 3);
c.weightx = weight;
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.CENTER;
c.gridy = 1;
for (int j = 0; j < lables.length; j++) {
c.gridx = j;
JLabel l = new JLabel(lables[j]);
product.add(l, c);
}
for (int i = 0; i < rows; i++) {
c.gridy++;
for (int j = 0; j < lables.length; j++) {
c.gridx = j;
JTextField f = new JTextField();
product.add(f, c);
}
}
c.gridy++;
c.gridx = 0;
c.anchor = GridBagConstraints.NORTHWEST;
c.fill = GridBagConstraints.NONE;
JPanel b = new JPanel();
JButton add = new JButton("+");
b.add(add);
JButton delete = new JButton("-");
b.add(delete);
product.add(b, c);
return product;
}
public static void main(String[] args) throws IOException {
JFrame frame = new JFrame("Debate Calculator");
JPanel debates = new JPanel();
frame.add(createLayout(5), BorderLayout.NORTH);
frame.pack();
frame.setVisible(true);
}

The problem is that you components are not equally sized to begin with. I can't explain exactly why it does what it does, but the size of your labels is each different because they have a different number of characters. I know you tried to make then the same size, but a " " is not the same as "W".
I changed your code to use the following and it seems to work:
JTextField f = new JTextField(10);
Now the width of each text field is greater than the label, so that is the width that is used to give each column a proportional size.
You might consider using a GridLayout. The default behaviour is to make each cell the same size.

The problem is your button bar at the bottom. Set the gridwidth to REMAINDER on that element.

Related

How to center text in one grid of a button that span in two grids?

I am trying to recreate Mac Calculator GUI. I use Swing and GridBagLayout for this project.
I manage to put 0 in a button that span in 2 column grid but I want to center it in the first column grid instead of 2 column grid.
Basically I want to the button to look exactly like:
.
In the calculator, the first column grid (consists of button "AC", "1", "4", "7" and "0") has the texts center evenly.
Here I try to use setHorizontalAlignment(SwingConstants.LEFT) but the result is not what I want.
JButton bt
n_0 = new JButton("0");
btn_0.setHorizontalAlignment(SwingConstants.LEFT);
GridBagConstraints gbc_btn_0 = new GridBagConstraints();
gbc_btn_0.fill = GridBagConstraints.HORIZONTAL;
gbc_btn_0.gridwidth = 2;
gbc_btn_0.insets = new Insets(0, 0, 5, 5);
gbc_btn_0.gridx = 0;
gbc_btn_0.gridy = 5;
frame.getContentPane().add(btn_0, gbc_btn_0);
Is it possible to achieve or are there alternative way to do this?
Do you absolutely need buttons ? I'm not used to the Mac, but if those calculator keys don't require an actual "button" behaviour (3D effect, moving the text when pressed, etc), maybe a plain JPanel would do.
In that case, if your "0" key is a JPanel, applying a GridLayout(1,2) to it and putting a JLabel("0") in the first cell and nothing in the second one would probably achieve the result you want.
Now of course you'll need handle click and key events at the JPanel level (look for example at this answer for more) but I think it would be a "clean" (from a component hierarchy point of view) way of doing it.
Update: Here is what I mean (part between ### comments):
import javax.swing.*;
import javax.swing.border.LineBorder;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class Calculator {
public static final Color CALC_BACKGROUND = new Color(44, 45, 47);
public static final Color KEY_BG_LAST_OPERATION = new Color(255,159,12);
public static final Color KEY_BG_NUMBER = new Color(96,97,99);
public static final Color KEY_BG_SPECIAL = new Color(64,65,67);
public static final Font BUTTON_FONT = new Font("SansSerif", Font.PLAIN, 30);
private static JComponent make0Button(String text) {
JPanel panel = new JPanel();
panel.setBorder(new LineBorder(CALC_BACKGROUND));
panel.setBackground(KEY_BG_NUMBER);
final JLabel label = new JLabel(text);
label.setFont(BUTTON_FONT);
label.setForeground(Color.WHITE);
label.setHorizontalAlignment(JLabel.CENTER);
label.setVerticalAlignment(JLabel.CENTER);
//#######################################
// The "0" key is a panel with two cells
panel.setLayout(new GridLayout(1, 2));
// The "0" text on the left
panel.add(label);
// A blank (dummy) label on the right
panel.add(new JLabel(" "));
//#######################################
panel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println(text);
}
});
return panel;
}
private static JComponent makeStdButton(String text, Color color) {
JPanel panel = new JPanel();
panel.setBorder(new LineBorder(CALC_BACKGROUND));
panel.setBackground(color);
panel.setLayout(new GridLayout(1, 1));
JLabel label = new JLabel(text);
label.setFont(BUTTON_FONT);
label.setForeground(Color.WHITE);
label.setHorizontalAlignment(JLabel.CENTER);
label.setVerticalAlignment(JLabel.CENTER);
panel.add(label);
panel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println(text);
}
});
return panel;
}
public static void addComponentsToPane(Container container) {
container.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
// Result (top)
c.anchor = GridBagConstraints.EAST;
c.fill = GridBagConstraints.BOTH;
c.gridwidth = 4;
c.gridx = 0; c.gridy = 0;
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.setBackground(CALC_BACKGROUND);
final JLabel resultLabel = new JLabel("0");
resultLabel.setFont(new Font("SansSerif", Font.PLAIN, 100));
resultLabel.setForeground(Color.WHITE);
panel.add(resultLabel, BorderLayout.EAST);
container.add(panel, c);
// Special "0" key
c = new GridBagConstraints();
c.anchor = GridBagConstraints.CENTER;
c.fill = GridBagConstraints.BOTH;
c.gridwidth = 2;
c.gridx = 0; c.gridy = 5;
container.add(make0Button("0"), c);
// All other keys
c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.gridwidth = 1;
c.weightx = 1;
c.weighty = 1;
c.gridx = 0; c.gridy = 1;
container.add(makeStdButton("AC", KEY_BG_SPECIAL), c);
c.gridx = 1; c.gridy = 1;
container.add(makeStdButton("+/-", KEY_BG_SPECIAL), c);
c.gridx = 2; c.gridy = 1;
container.add(makeStdButton("%", KEY_BG_SPECIAL), c);
c.gridx = 3; c.gridy = 1;
container.add(makeStdButton("/", KEY_BG_LAST_OPERATION), c);
c.gridx = 0; c.gridy = 2;
container.add(makeStdButton("7", KEY_BG_NUMBER), c);
c.gridx = 1; c.gridy = 2;
container.add(makeStdButton("8", KEY_BG_NUMBER), c);
c.gridx = 2; c.gridy = 2;
container.add(makeStdButton("9", KEY_BG_NUMBER), c);
c.gridx = 3; c.gridy = 2;
container.add(makeStdButton("x", KEY_BG_LAST_OPERATION), c);
c.gridx = 0; c.gridy = 3;
container.add(makeStdButton("4", KEY_BG_NUMBER), c);
c.gridx = 1; c.gridy = 3;
container.add(makeStdButton("5", KEY_BG_NUMBER), c);
c.gridx = 2; c.gridy = 3;
container.add(makeStdButton("6", KEY_BG_NUMBER), c);
c.gridx = 3; c.gridy = 3;
container.add(makeStdButton("-", KEY_BG_LAST_OPERATION), c);
c.gridx = 0; c.gridy = 4;
container.add(makeStdButton("1", KEY_BG_NUMBER), c);
c.gridx = 1; c.gridy = 4;
container.add(makeStdButton("2", KEY_BG_NUMBER), c);
c.gridx = 2; c.gridy = 4;
container.add(makeStdButton("3", KEY_BG_NUMBER), c);
c.gridx = 3; c.gridy = 4;
container.add(makeStdButton("+", KEY_BG_LAST_OPERATION), c);
c.gridx = 2; c.gridy = 5;
container.add(makeStdButton(".", KEY_BG_NUMBER), c);
c.gridx = 3; c.gridy = 5;
container.add(makeStdButton("=", KEY_BG_LAST_OPERATION), c);
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("Calculator");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
addComponentsToPane(frame.getContentPane());
frame.setSize(400,600);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGUI());
}
}
Looks to me it's quite close to the expected layout... (with clicks, see console)
I recommend you to use:
mig_layout library.
allows you to make easy/adaptable designs and you can solve your problem.

Issue with changing JButton size

I'm trying to make a mine sweeper game with Swing library (just for training).
I spotted a problem when I tried to change size of a button with setSize() method (part of Container class). One of my previous program was able to handle that (with ActionListener)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ButtonChanger extends JFrame {
JButton big, small, dis;
JLabel message, poof;
public ButtonChanger(){
setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
message = new JLabel("Click to make it");
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 0;
add(message, c);
big = new JButton("BIG");
big.setSize(30, 30); // no reaction for this call
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 1;
c.gridwidth = 1;
add(big, c);
small = new JButton("small");
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 1;
c.gridy = 1;
add(small, c);
dis = new JButton("disapear");
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 3;
c.gridy = 1;
add(dis, c);
poof = new JLabel(" poof!");
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 3;
c.gridy = 1;
poof.setVisible(false);
add(poof, c);
big.setSize(300,300); // same story
event a = new event();
big.addActionListener(a);
small.addActionListener(a);
dis.addActionListener(a);
}
public class event implements ActionListener{
public void actionPerformed(ActionEvent a){
String op = a.getActionCommand();
if(op.equals("BIG")){
big.setSize(50,50); // finaly!
} else if(op.equals("small")){
small.setSize(10,10);
} else if(op.equals("disapear")){
dis.setVisible(false);
poof.setVisible(true);
}
}
}
public static void main(String args[]){
ButtonChanger gui = new ButtonChanger();
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gui.setVisible(true);
gui.setSize(250,250);
gui.setTitle("");
}
}
But when I tried to use same solution here - nothing happened.
import java.util.Random;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Board extends JPanel
implements ActionListener{
private Integer pixelWidth;
private Integer pixelHeight;
public Field[][] board;
private Random generator = new Random();
public Board(int width,int height){ // width - x axis scaled with "button" unit
// height - y axis scaled with "button" unit
setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
board = new Field[width][height];
pixelWidth = width * Field.fieldW;
pixelHeight = height * Field.fieldH;
for(int i = 0;i < height;i++)
for(int j = 0;j < width;j++){
board[i][j] = new Field(generator.nextBoolean());
}
for(int i = 0;i < height;i++){
c.fill = GridBagConstraints.HORIZONTAL;
c.gridy = i;
for(int j = 0;j < width;j++){
c.gridx = j;
add(board[i][j].getFieldButton(),c);
add(board[i][j].getFieldLabel(),c);
}
}
/* for(int i = 0;i < height;i++)
for(int j = 0;j < width;j++){
board[i][j].setField();
}*/
}
public void actionPerformed(ActionEvent e){
String co = e.getActionCommand();
if(co.equals(" ")){ // button is single space sign
for(int i = 0;i < 10;i++)
for(int j = 0;j < 10;j++){
board[i][j].setField(); //inside this method is call for setSize() for fieldButton
}
}
}
}
Previously I changed Board class to make it inhetitate after JFrame (set up as main GUI frame in whole code) but that gave me same output as original.
Did I mess up something?
big = new JButton("BIG");
big.setSize(30, 30); // no reaction for this call
c.fill = GridBagConstraints.HORIZONTAL;
There is no reaction for big.setSize... because then in GridBagConstraints you set fill to horizontal, so button will be "stretched" to fill horizontally.
Instead use c.fill = GridBagConstraints.NONE
fill
Used when the component's display area is larger than the component's requested size to determine whether and how to resize the component. Valid values (defined as GridBagConstraints constants) include NONE (the default), HORIZONTAL (make the component wide enough to fill its display area horizontally, but do not change its height), VERTICAL (make the component tall enough to fill its display area vertically, but do not change its width), and BOTH (make the component fill its display area entirely).
You can read more here: https://docs.oracle.com/javase/tutorial/uiswing/layout/gridbag.html

How to make grids different in GridBagLayout in Java?

what I want to achieve is something like this:
This is my code:
JDialog messageDialog = new JDialog();
messageDialog.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
messageDialog.setBounds(0, 0, 350, 250);
messageDialog.setLocationRelativeTo(null);
messageDialog.setVisible(true);
JPanel btnPanel = new JPanel();
JPanel clearPanel = new JPanel();
JPanel labelsPanel = new JPanel();
JPanel txtPanel = new JPanel();
JButton newMessage = new JButton("New");
JButton recievedMessages = new JButton("Recieved");
JButton sendMessages = new JButton("Sent");
JButton refreshMessages = new JButton("Refresh");
JLabel recievedMessLab = new JLabel("Messages get:");
JTextPane txtToSend = new JTextPane();
btnPanel.setLayout(new GridLayout(4, 1));
btnPanel.add(newMessage);
btnPanel.add(recievedMessages);
btnPanel.add(sendMessages);
btnPanel.add(refreshMessages);
c.gridx = 0;
c.gridy = 0;
messageDialog.add(clearPanel, c);
c.gridx = 1;
c.gridy = 0;
messageDialog.add(labelsPanel, c);
c.gridx = 0;
c.gridy = 1;
messageDialog.add(btnPanel, c);
c.gridx = 1;
c.gridy = 1;
messageDialog.add(txtPanel, c);
labelsPanel.add(recievedMessLab);
I don't know why I get some free space around all the panels and I can't figure out how to resize the grids. Oracle tutorial doesn't help too. What is the easiest way to resize this? How to rid of that free space?
You need to add weight and fill information to your GridBagConstraints so the layout manager knows which components to strech over the available space.
Try the following:
c.gridx = 0;
c.gridy = 0;
c.fill = c.NONE; // dont fill (strech)
messageDialog.add(clearPanel, c);
c.gridx = 1;
c.gridy = 0;
c.weightx = 1; // horizontal weight: 1
c.fill = c.HORIZONTAL; // fill (strech) horizontally
messageDialog.add(labelsPanel, c);
c.gridx = 0;
c.gridy = 1;
c.weightx = 0; // horizontal weight: back to 0
c.weighty = 1; // vertical weight: 1
c.fill = c.VERTICAL; // fill (strech) vertically
messageDialog.add(btnPanel, c);
c.gridx = 1;
c.gridy = 1;
c.weightx = 1; // both weights: 1
c.weighty = 1; // both weights: 1
c.fill = c.BOTH; // and fill both ways, vertically and horizontally
messageDialog.add(txtPanel, c);
Revisit the part about weightx, weighty and fill in the tutorial to get a clue how they work.
PS: txtPanel is empty and txtToSend is never used?

Weird layout using GridBagConstraints

I have several methods which create their own component, JButton or JLabel in a JPanel. Then I have a separate method which adds all these JPanels the the JFrame. I also use gridx and gridy on the JPanels to position them how I want. This is: lookreply on the left, then top right the title and below in a 2X2 table quit, restart, pickup and hello. However my current code when run displays a weird, random layout.
The lookreply is on the left, but then to the right is quit, a space, restart then hello all vertical. pickup and title aren't seen. I dont know why this is happening.
Please see my code below.:
public class GUI extends JPanel
{
/**
* Creation of variables used throughout the GUI Class.
*/
//JPanel panel = new JPanel(new GridBagLayout());
private static final long serialVersionUID = 1L;
public static void main(String[] args)
{
GUI g = new GUI();
g.create();
}
private void create()
{
JFrame screen = new JFrame("Dungeon of Doom");
screen.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
screen.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
//set size to full screen.
screen.setExtendedState(Frame.MAXIMIZED_BOTH);
//Add all JPanes to screen
screen.add(lookReply(), c);
c.gridy = 0;
c.gridx = 0;
screen.add(title(), c);
c.gridy = 0;
c.gridx = 1;
c.gridwidth = 2;
screen.add(quit(), c);
c.gridy = 1;
c.gridx = 1;
screen.add(restart(), c);
c.gridy = 1;
c.gridx = 2;
screen.add(pickup(), c);
c.gridy = 2;
c.gridx = 1;
screen.add(hello(), c);
c.gridy = 2;
c.gridx = 2;
screen.setVisible(true);
}
One of the methods (quit)
private JPanel quit()
{
JPanel quitPanel = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
JButton quit = new JButton("QUIT");
quitPanel.add(quit, c);
return quitPanel;
}
All the other methods are pretty much the same except the title is a a JLabel and the table iterates to create a 5x5 table of JLabel within its own JPanel. Any help is appreciated!
I have found what was doing this.
As seen in the code I was adding the component before setting the layout.
screen.add(lookReply(), c);
c.gridy = 0;
c.gridx = 0;
whereas it should be
c.gridy = 0;
c.gridx = 0;
screen.add(lookReply(), c);

GridBagLayout & JScrollPane: how to reduce row height?

See below a simple test code using a GridBagLayout (2 rows, 2 component on row 0, 1 component on row 1). Although I have specified weighty to be 0.01 for first row and 1 for second row, the ratio on the screen looks more like 0.3 vs. 0.7. It seems that the height of the first row is resized so that the whole textarea fits in it.
How can I reduce the height of the first row, so that the scroll bars of the JScrollPane will appear?
public class Test {
public static void main(String... args) {
String text = "text\n\n\n\n\n\n\n\ntext";
JFrame frame = new JFrame();
JTextArea area;
JScrollPane pane;
JPanel desktop = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 0;
c.weightx = 0.25;
c.weighty = 0.05;
area = new JTextArea(text);
area.setBackground(Color.RED);
pane = new JScrollPane(area);
desktop.add(pane, c);
c.gridx = 1;
c.gridy = 0;
c.weightx = 0.75;
c.weighty = 0.05;
area = new JTextArea(text);
area.setBackground(Color.BLUE);
pane = new JScrollPane(area);
desktop.add(pane, c);
c.fill = GridBagConstraints.BOTH;
c.gridx = 0;
c.gridy = 1;
c.weightx = 0;
c.weighty = 1;
c.gridwidth = 2;
area = new JTextArea(text);
area.setBackground(Color.GREEN);
pane = new JScrollPane(area);
desktop.add(pane, c);
frame.setContentPane(desktop);
frame.setPreferredSize(new Dimension(800, 600));
frame.pack();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
}
}
Set the number of rows on the JTextArea so that the preferredSize of the textarea and scrollpane will adjust to that number of rows. In case there is an excessive number of rows in the text of the textarea, the scrollbar will appear.
weight - Specifies how to distribute extra vertical space. So if available space is bigger than sum of preferred sizes then extra pixes are distributed according to the weight values.

Categories