Java - Resize buttons in GridBagLayout - java

how can I make the buttons height a bit bigger and the width of right and left columns on the same size. I have tried weightx weighty heightx heighty but it didn't work. Thanks in advance. Here's my code:
Container contentPane = getContentPane();
contentPane.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.insets = new Insets(20,20,20,20);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1.0;
JButton back = new JButton("Back to previous menu");
c.gridx = 1;
c.gridy = 0;
contentPane.add(back,c);
JLabel welcome = new JLabel("Hi secretary, please select an action");
c.gridx = 0;
c.gridy = 0;
contentPane.add(welcome,c);
There's more code of buttons definition but it's just positioning themselves on the layout.

Do not set the preferred size of your buttons. This will cause serious visual issues for users who have desktop fonts which are different from yours.
You should let the button define its own preferred size. The best way to augment the preferred height is with GridBagConstraints.ipady:
c.ipady = 24;
Another option is to use JButton.setMargin to give each button an additional margin:
Insets margin = new Insets(12, 0, 12, 0);
back.setMargin(margin);
welcome.setMargin(margin);
Forcing the left and right sides to have equal widths is more difficult. GridBagLayout is not capable of doing that. The weightx field only determines the distribution of extra space, when the window is wider than it needs to be in order to accommodate all child components’ preferred sizes. If the columns have different widths to begin with, distributing the extra space with weightx will not make their widths equal.
Personally, I don’t think forcing the two sides to have equal widths will add any value. If you insist on the left and right sides being exactly equal width, you will have to abandon the use of GridBagLayout. SpringLayout can do it, but it’s difficult to use. If you’re willing to introduce a third-party dependency, something like MiG Layout may be able to do it.

Related

How do I put text fields and buttons under each other? [duplicate]

What I mean by a JLabel-JTextField pair is a JLabel component followed by a JTextField one, for example, "Parameter 1: -----" where "-----" denotes a blank JTextField.
The problem is, the width of JLabels varies due to the varying lengths of parameter names, so that the starts of JTextFields are not aligned vertically.
Is there any way to align the JLabels vertically to their right, so that the starts of JTextFields that follow would be aligned? Thanks.
Is there any way to align the JLabels vertically to their right, so that the starts of JTextFields that follow would be aligned?
1.6+, GroupLayout. E.G. from the JavaDocs:
Use the label alignment that pushes the text to the RHS.
See also this answer for an MCVE.
You didn't specify which layout do you use, so a good layout to implement that would be GridBagLayout. The demo in oracle site is great to start with.
And a short example:
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
panel.add(new JLabel("Label 1:"), c);
c.gridx = 1;
c.gridy = 0;
panel.add(new JTextField("TextField 1"), c);
c.gridx = 0;
c.gridy = 1;
panel.add(new JLabel("Label 2:"), c);
c.gridx = 1;
c.gridy = 1;
panel.add(new JTextField("TextField 2"), c);
or
there is possible align just text inside JTextComponents with
JLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
This is a perfect use case for DesignGridLayout:
DesignGridLayout layout = new DesignGridLayout(contentPane);
layout.labelAlignment(LabelAlignment.RIGHT);
layout.row().grid(label1).add(field1);
layout.row().grid(label2).add(field2);
...
I would suggest the GridLayout layout manager. It presents the easiest solution to show pair-wise visualization of label and textbox controls. Thereby you simply define the number of rows and columns at time of instantiation and the added controls will be handled by the manager.
Good solutions for this that I've seen include use of the GridBagLayout (as noted above) or the MiGLayout, though since the latter isn't part of standard Java, it must be downloaded and placed on the classpath prior to use. MiGLayout is not as difficult to use.
The LayoutManager of the parent component has the responsability of positioning the elements contained. Maybe you need to set an XYLayout.
See the setLayoutManager() for your parent class.

Multiple GridBagConstraints?

I'm a bit confused, is it possible to have multiple GridBagConstraints?
I have two panels using GridBagLayout, both affected by the same constraints. This gives me an issue when it comes to putting smaller components next to larger ones as illustrated below. The size of the panel on the left, means the cell on that row is very large, centering the panel on the right and it's components. I've tried using separate constraints for each panel but I haven't seen any differences, I think I'm doing something wrong.
How can I achieve two panels positioned next to each other, however have the components of each influenced by separate constraints?
Here's what I currently have:
Created with:
// layout
GridBagConstraints c = new GridBagConstraints();
// components
JPanel supplier = new JPanel(new GridBagLayout());
// grab the suppliers
Suppliers.Supplier[] suppliers = new Suppliers.Supplier[Suppliers.supplier.size()];
for (int i = 0; i < Suppliers.supplier.size(); i++) {
suppliers[i] = Suppliers.supplier.get(i);
}
JPanel resultsPanel = new JPanel();
JScrollPane scrollpane = new JScrollPane(resultsPanel, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollpane.setPreferredSize(new Dimension(120, 300));
// style properties
c.gridx = 0;
c.gridy = 0;
c.insets = new Insets(10, 10, 10, 10);
supplier.add(scrollpane, c);
int position = 0;
for (int i = 0; i < Suppliers.supplier.size(); i++) {
b_supplierSuppliers.add(new JButton(suppliers[i].getName()));
b_supplierSuppliers.get(i).setActionCommand(suppliers[i].getId());
b_supplierSuppliers.get(i).addActionListener(this);
// style properties
c.gridx = 0;
c.gridy = position;
c.insets = new Insets(10, 10, 10, 10);
c.gridwidth = 1;
resultsPanel.add(b_supplierSuppliers.get(i), c);
position++;
}
JPanel resultsPaneltwo = new JPanel(new GridBagLayout());
// style properties
c.gridx = 1;
c.gridy = 0;
supplier.add(resultsPaneltwo, c);
// code label
l_supplierCode = new JLabel("Supplier Code");
// style properties
c.gridx = 1;
c.gridy = 0;
c.insets = new Insets(0, 10, 10, 10);
c.gridwidth = 4;
c.fill = 4;
resultsPaneltwo.add(l_supplierCode, c);
However I'm after:
Any help is much appreciated.
First, to answer your initial question. Yes, you should use different GridBagConstraints objects for each component. It's worth noting however that it is not essential to create new ones for each component, and changes to the constraint after it has been assigned to another won't affect the earlier component's position. So, for the sake of readability and later debugging it is worth declaring multiple constraints but it's not essential.
Also, it looks as though you need to specify a weighty for your constraint on your right cell. By default cells are centered in any spare space. In order to specify where that extra space is placed (vertically for y, and horizontally for x), you need to give the constraint a weight value;
c.weighty = 1;
This should make it so all extra vertical space is allocated to that cell's constraint, and as such push the cell to the top. If you create a second constraint and do the following;
c2.weighty = 1;
The extra space would be spread evenly between those two cell's constraints.I hope this helps. Let me know how you get on.
The official Oracle GridBagLayout guide says the following on the weight attributes;
weightx, weighty
Specifying weights is an art that can have a
significant impact on the appearance of the components a GridBagLayout
controls. Weights are used to determine how to distribute space among
columns (weightx) and among rows (weighty); this is important for
specifying resizing behavior. 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.
Generally weights are specified with 0.0 and 1.0 as the extremes: the
numbers in between are used as necessary. Larger numbers indicate that
the component's row or column should get more space. For each column,
the weight is related to the highest weightx specified for a component
within that column, with each multicolumn component's weight being
split somehow between the columns the component is in. Similarly, each
row's weight is related to the highest weighty specified for a
component within that row. Extra space tends to go toward the
rightmost column and bottom row.

Allowing User to Resize JScrollPane

When the user moves the cursor over to the border of the JScrollPane, can I turn the cursor into two little arrows that are pointing at the opposite directions of each other thus the user may shrink or grow the entire JScrollPane?
JScrollPane scrollPane = new JScrollPane(buddyList,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
layoutConstraints.gridx = 0; layoutConstraints.gridy = 0;
layoutConstraints.gridwidth = 3; layoutConstraints.gridheight = 8;
layoutConstraints.fill = GridBagConstraints.BOTH;
layoutConstraints.insets = new Insets(10, 6, 10, 36);
layoutConstraints.anchor = GridBagConstraints.NORTHWEST;
layoutConstraints.weightx = 0.8; layoutConstraints.weighty = 1.0;
layout.setConstraints(scrollPane, layoutConstraints);
add(scrollPane);//Adds the Scrollpane straight to the panel The class extends JPanel
You are looking at the wrong place. If you want to allow resizing of the scrollpane, the scrollpane is the wrong object to look at. It’s the responsibility of the parent container (or its layout manager) to give or take space from the component (which happens to be a scrollpane here) and distribute it to other children. The simplest way is to put the scrollpane into a split pane. You may put the split pane into another split pane with a different orientation to allow resizing in both direction, however this will resize the direct neighbor of the scroll pane (the other child of the inner split pane) as well. There is no solution to this with all these layouts forming a kind of grid.
Note that with your currently used GridBagLayout in the parent container it’s very hard to achieve such a resize support. And even if you implement this tricky trick the GridBagLayout will always size entire rows or columns. Thus you will have the same problem as with nested split panes even worse.

How do you stop a JLabel changing its size when its text changes?

I'm generating some JComponents in code and using the GridBag layout to arrange them. My layout consists of 12 rows and 3 columns, with each row consisting of a JSlider, a JCheckBox and a JLabel. Here's the code I'm using to generate the UI:
final int NUM_MOTORS = 12;
// This is the panel I'm adding the components to.
pnlMotorSliders.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
for (int i = 0; i < NUM_MOTORS; ++i) {
c.gridy = i;
// Create the slider
JSlider slider = new JSlider(SwingConstants.HORIZONTAL, 10, 4085, 10);
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.weightx = 0.9;
pnlMotorSliders.add(slider, c);
// Create the checkbox
JCheckBox checkBox = new JCheckBox();
checkBox.setOpaque(true);
checkBox.setBackground(Color.blue);
c.fill = GridBagConstraints.NONE;
c.gridx = 1;
c.weightx = 0.1;
pnlMotorSliders.add(checkBox, c);
// Create the current label
JLabel label = new JLabel("0");
label.setBorder(BorderFactory.createLineBorder(Color.red));
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 2;
c.weightx = 0.2;
pnlMotorSliders.add(label, c);
}
The problem I'm having is that when I set the text in any of the JLabels, they change their width and affect the rest of the layout, even if the width of the text that I'm setting appears to be much smaller than the width of the JLabel. The following two screenshots demonstrate what I mean (the red and blue borders were for debugging purposes):
I've set the text on the bottom JLabel to "-12". Even though the JLabel appears to be much wider than the text, it has changed its size, affecting the rest of the layout.
Why is this happening and what can I do to prevent it?
You can fix the size of the labels by setting the minimum, prefered and maximum size:
label.setMinimumSize(width, height);
label.setPreferedSize(width, height);
label.setMaximumSize(width, height);
Also make sure to set the GridBagConstraints#fill to NONE, although I am not sure if that is still neccessary (I think it is).
EDIT: btw, to get rid of those nasty dashed lines around the focused Component, you can just set it to be not focusable:
slider.setFocusable(false);
The set-the-preferred-size solution works only if you don't have the components horizontally fill their bag in the GridBagLayout.
Another solution is to remove the weight you have placed on components in that column of your GridBagLayout. You can then control the column width manually. An easy way to do so (at design time) is to place a JLabel in the column with zero height and the specific width you desire.
Why is this? You need to dig into how GridBagLayout works:
The GridBagLayout sizes its columns based on the space required, and then uses the weights to allocate the "left over" space so that the resulting column widths then add up to the total width of the panel. The space required for each column is computed by finding the widest of the components in that column.
The space required for each component is determined by asking it what width it would prefer. In your case, a JLabel with "0" is smaller than a JLabel with "-12" and so the column is changing size.
The left over space is allocated based on the horizontal weights assigned to components in each column. The weights are totaled and percentages for each column are determined based on that column's percent of the total.
The column size is determined based on the space required PLUS the left over space. So, if all your components in the column have no weight then you'll not get any left over space, and hence not get dynamic changes.
A third solution is to just not use GridBagLayout.
Explicitely set the preferred size of your labels using JLabel#setPreferredSize(Dimension).
This way, you lock the size of the component, and tell the layout manager not to resize it.
label.setPreferredSize(new Dimension(width, height));
This was only way i could find to make it work. Setting a Minimum and/or a Maximum didn't do anything for me. Also, for me on java 8 i needed to use a Dimension, or there was no change to the previous, inappropriate sizes.

How to align JLabel-JTextField pairs vertically

What I mean by a JLabel-JTextField pair is a JLabel component followed by a JTextField one, for example, "Parameter 1: -----" where "-----" denotes a blank JTextField.
The problem is, the width of JLabels varies due to the varying lengths of parameter names, so that the starts of JTextFields are not aligned vertically.
Is there any way to align the JLabels vertically to their right, so that the starts of JTextFields that follow would be aligned? Thanks.
Is there any way to align the JLabels vertically to their right, so that the starts of JTextFields that follow would be aligned?
1.6+, GroupLayout. E.G. from the JavaDocs:
Use the label alignment that pushes the text to the RHS.
See also this answer for an MCVE.
You didn't specify which layout do you use, so a good layout to implement that would be GridBagLayout. The demo in oracle site is great to start with.
And a short example:
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
panel.add(new JLabel("Label 1:"), c);
c.gridx = 1;
c.gridy = 0;
panel.add(new JTextField("TextField 1"), c);
c.gridx = 0;
c.gridy = 1;
panel.add(new JLabel("Label 2:"), c);
c.gridx = 1;
c.gridy = 1;
panel.add(new JTextField("TextField 2"), c);
or
there is possible align just text inside JTextComponents with
JLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
This is a perfect use case for DesignGridLayout:
DesignGridLayout layout = new DesignGridLayout(contentPane);
layout.labelAlignment(LabelAlignment.RIGHT);
layout.row().grid(label1).add(field1);
layout.row().grid(label2).add(field2);
...
I would suggest the GridLayout layout manager. It presents the easiest solution to show pair-wise visualization of label and textbox controls. Thereby you simply define the number of rows and columns at time of instantiation and the added controls will be handled by the manager.
Good solutions for this that I've seen include use of the GridBagLayout (as noted above) or the MiGLayout, though since the latter isn't part of standard Java, it must be downloaded and placed on the classpath prior to use. MiGLayout is not as difficult to use.
The LayoutManager of the parent component has the responsability of positioning the elements contained. Maybe you need to set an XYLayout.
See the setLayoutManager() for your parent class.

Categories