GridBagLayout Assistance - java

I've tried all combinations and looked at all the documentation but I can't figure out how to use GridBagLayout.
I've got 3 components in a JPanel with GridBagLayout being the LayoutManager of the JPanel and using GridBagConstraints on the 3 components.
With the current code (as shown below) the 3 elements appear on the panel properly. The issue is that the first component is a JLabel which sometimes is quite long, if this is the case then it will expand and make the other 2 components smaller.
My objective is to have a JPanel with a GridBagLayout of 1 row and 4 columns, where the first element takes up the first 2 columns, and the other 2 elements take up the remaining 2, and that these elements to do not expand out of their columns.
private static void setConstraints(GridBagConstraints constraints, int gridx, int gridy, int weightx, Insets insets) {
constraints.gridx = gridx;
constraints.weightx = weightx;
constraints.insets = insets;
}
gridBagLayout = new GridBagLayout();
constraints = new GridBagConstraints();
centerPanel = new JPanel(gridBagLayout);
constraints.fill = GridBagConstraints.HORIZONTAL;
fileNameLabel = new JLabel("Resolving: '" + EngineHelpers.trimStringToFitPanel(urlTextField.getText(), 70) + "'");
setConstraints(constraints, 0, 0, 2, new Insets(0, 5, 5, 0));
gridBagLayout.setConstraints(fileNameLabel, constraints);
progressBar = new JProgressBar();
progressBar.setStringPainted(true);
setConstraints(constraints, 1, 0, 1, new Insets(0, 5, 5, 0));
gridBagLayout.setConstraints(progressBar, constraints);
cancelDownloadButton = new JButton("Cancel");
setConstraints(constraints, 2, 0, 1, new Insets(0, 0, 0, 0));
gridBagLayout.setConstraints(cancelDownloadButton, constraints);
centerPanel.add(fileNameLabel);
centerPanel.add(progressBar);
centerPanel.add(cancelDownloadButton);
Thanks in advance everyone, sorry for the stupid question!

You probably want weightx set to 0 for both the button and progress bar. For the label, set the weight to 1. This will keep the button and progress bar from expanding at all and let the progress bar take all the extra space.
Also set gridwidth on the progress bar constraints to 2 so it actually uses 2 columns.
Finally, depending on where centerPanel is placed, it may not actual expand to fill the container. If centerPanel is being placed in a parent with a BorderLayout, it should expand. To make sure, you can add a border with centerPanel.setBorder(BorderFactory.createLineBorder(Color.RED)) for debugging. This can also be useful on the button, label and progress bars too.

Related

Word wrapping a JLabe/JTextArea in a JPanel in a JScrollPane

In my application, I need to word wrap Labels, which are contained in a JPanel (with GridBagLayout), which in turn is contained in a JScrollPane, which is contained in a resizable JFrame. The text should always be as wide as the Scrollpane allows(i.e. be completly visible at once). I tried multiple things already:
Putting tags around the text.
Result: Nothing
Putting on the Text
Result: Wraps, but with static width (does not respond to the Frame being resized) (duh)
Putting on the Text
Result: Nothing
Using a JTextArea, as in https://stackoverflow.com/a/26426585/4936150
Result: Appears to work at first, when the width of the Frame is increased, the words get "unwrapped" (so they are all on one line), but when the width is decreased afterwards, it will stay that way and not "wrap back". Also, weirdly doesn't work in the Nimbus L&F
Implementing Scrollable on the JPanel and returning true from getScrollableTracksViewportWidth()
Result: Works, but I DO want it to scroll horizontally if the Frame is too small for other Components
For reference, here is the source for my Panel class, without any wrapping:
public class ProgPanel extends JPanel {
/**
* Create the panel.
*/
public ProgPanel() {
GridBagLayout gridBagLayout = new GridBagLayout();
gridBagLayout.columnWidths = new int[]{0};
gridBagLayout.rowHeights = new int[]{59, 0, 0};
gridBagLayout.columnWeights = new double[]{1.0};
gridBagLayout.rowWeights = new double[]{0.0, 1.0, Double.MIN_VALUE};
setLayout(gridBagLayout);
JLabel lblName = new JLabel("Long, long text taht needs to be wrapped, because it is displayed in a very big font on a kindof small screen, bla bla bla bhlergh lol rofl 1337");
GridBagConstraints gbc_lblName = new GridBagConstraints();
gbc_lblName.gridwidth = 2;
gbc_lblName.anchor = GridBagConstraints.WEST;
gbc_lblName.insets = new Insets(0, 0, 5, 0);
gbc_lblName.gridwidth = 1;
gbc_lblName.gridx = 0;
gbc_lblName.gridy = 0;
add(lblName, gbc_lblName);
lblName.setBorder(new EmptyBorder(10, 5, 0, 10));
lblName.setIconTextGap(10);
lblName.setIcon(new ImageIcon("someicon.png"));
lblName.setFont(getFont().deriveFont(Font.BOLD+Font.ITALIC, 48));
}
}
EDIT: Here is the implementation using a JTextArea, which will only grow in width, but not shrink: https://pastebin.com/egMXfwK1 (Pastebin due to long length and tedious SO formatting)
EDIT2: Here are some pictures showing the issue: http://imgur.com/a/mhtV9

JList border disappears on scrolling

I've five lists (enclosed in a jscrollpane) added to a jpanel in a group layout. The problem with the lists is that when a scrollbar appears automatically, the border on the bottom/top disappears (lists 2,3,4). How do I make sure that all lists look the same w.r.t border just like the first/last lists?
I've tried setting viewportborder using setViewPortBroder, but it doesn't change things much. 2,3,4 appear with light border while the rest of the lists have double borders.
EDIT
Adding code sample:
Each list you see is created using this code:
MyJList jList = new MyJList(value);
jList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
jList.setModel(listModel);
jList.setMinimumSize(new Dimension(135, 300));
jList.setMaximumSize(new Dimension(135, 300));
jList.clearSelection();
jList.setSelectionBackground(Color.darkGray);
jList.setSelectionForeground(Color.white);
jList.setBorder(new LineBorder(Color.darkGray, 1));
jList.setFixedCellHeight(30);
jList.setFixedCellWidth(100);
Font font = jList.getFont();
jList.addListSelectionListener(new ListListener());
return jList;
MyList is an extension of JList. It does nothing special, other than storing some domain related metadata. And, then lists are added to the middle panel like this:
private void layoutLists(JLabel[] labels, JList[] lists) {
panel.removeAll();
panel.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.NONE;
JScrollPane[] jScrollPanes = new JScrollPane[lists.length];
for (int index = 0; index < lists.length; index++) {
jScrollPanes[index] = new JScrollPane(lists[index]);
jScrollPanes[index].setBorder(BorderFactory.createEmptyBorder());
jScrollPanes[index].setMinimumSize(new Dimension(135, 300));
jScrollPanes[index].setMaximumSize(new Dimension(135, 300));
jScrollPanes[index].setPreferredSize(new Dimension(135, 300));
}
for (int index = 0; index < labels.length; index++) {
gbc.gridx = index;
gbc.gridy = 0;
gbc.insets = new Insets(8, 8, 8, 8);
panel.add(labels[index], gbc);
gbc.gridy = 1;
if (index == labels.length - 1) {
gbc.insets = new Insets(8, 8, 8, 13);
}
panel.add(jScrollPanes[index], gbc);
}}
The explanation of the top/bottom part of the inner (JList) border not being visible is that ... they are not visible if the vertical scrollBar appears (the list is scrolled off)
If you insist, either:
switch the borders - empty on the list itself and lineBorder on the scrollPane or
set the viewportBorderProperty of the scrollPane to the lineBorder
Beware: it's not recommended to fiddle with the default LAF settings - where-to or not the components have a border should be left to the ui to guarantee consistent visuals across your application. Nor does it look exactly good to have the left border line beside (either outside or inside) the scrollPane's vertical scrollbar.
Edit
Just noticed that you already tried the second option (and are not satisfied with the result :-) But then: where do you want the vertical border line if the scrollBar is visible? Anyway, back to the beware: the outcome is highly LAF dependent ...

Starting GridBagLayout from top left corner in Java Swing

I'm new to Java Swing and I have been struggling to start the GridBagLayout from top left corner so that c.gridx=0 c.gridy=0 will put my object on the top left corner.
I'd appreciate if you could help me by telling what I need to do after this point:
JPanel panel = new JPanel(new GridBagLayout());
frame.add(panel);
GridBagConstraints c = new GridBagConstraints();
I know that I have to use NORTHWEST or FIRST_LINE_START constants, but I don't know how. I tried to do it this way' but it did not realize the constants.
frame.getContentPane().add(panel, BorderLayout.NORTHWEST);
Thanks for your help.
Read the section from the Swing tutorial on How to Use GridBagLayout. The secton on "weightx,weighty" states:
Unless you specify at least one non-zero value for weightx or weighty, all the components clump together in the center of their container.
You need to use your GridBagConstraints' anchor property. This should do it for you:
frame.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.NORTHWEST;
frame.add(panel, gbc);
I'm not guaranteeing that you won't have to set other properties of the constraints object to get the layout you desire. In particular, you may need to set weightx and weighty to be 1 so that the panel takes up all of the available space given to it.
For those, who use IDE (e.g. NetBeans), I finally found nice trick: if you want to add components to top and use their preferred sizes: add another empty panel with weighty = 1.0. Copied from auto-generated code (NetBeans):
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.weighty = 1.0;
jPanelOptions.add(jPanelFiller, gridBagConstraints);
a quick and simple way:
add a blank JLabel to end of page:
// your code goes here
gbc.weightx = 1;
gbc.weighty = 1;
bg.add(new JLabel(" "), gbc); // blank JLabel
There's a workaround. You can put the GridBagLayout panel in a BorderLayout panel with BorderLayout.NORTH. Then Component in GridBagLayout panel will start from top position.
static void test4(){
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(480, 360);
JPanel borderLayoutPanel=new JPanel(new BorderLayout());
JPanel gridBagLayoutPanel = new JPanel(new GridBagLayout());
borderLayoutPanel.add(gridBagLayoutPanel, BorderLayout.NORTH);
frame.add(borderLayoutPanel);
JButton testButton=new JButton("test button");
GridBagConstraints c = new GridBagConstraints();
c.gridx=0;
c.gridy=0;
gridBagLayoutPanel.add(testButton, c);
frame.setVisible(true);
}
if you want the grid to go all the way to the top, simply set all your weighty = 0 until the last item, set it to any number greater than 0, it will effectively push the rest of the buttons to the top.
Don't forget to also increment your button's gridy value.
Otherwise it will be centered.
(the same can be done using gridx and weightx value if you arent using the c.fill = GridBagConstraints.HORIZONTAL property.)

Swing: easiest way to align width of [dynamic][static][dynamic] components?

What is the easiest way in standard Java Swing to align three components in such a way that:
the dynamic widths of Component1 and Component3 are adjusted to be equal,
while Component2 (which is in between) has constant width?
Imagine we have some resizable JPanel (such as inside a JFrame).
Small width should look like this:
[----------------whole JPanel----------------]
[--Component1--] [Component2] [--Component3--]
Big width should look like this:
[------------------------whole JPanel------------------------]
[------Component1------] [Component2] [------Component3------]
Note: I just "trialed-and-errored" with GroupLayout for too long.
One option is using a GridBagLayout. A quick and dirty snippet to get you started:
GridBagConstraints gbc;
final int A_CENTER = GridBagConstraints.CENTER; // anchor: center
final int F_NONE = GridBagConstraints.NONE; // fill: none
final int F_DX = GridBagConstraints.HORIZONTAL; // fill: dx only
final Insets IN_0 = new Insets(0, 0, 0, 0); // empty insets
setLayout(new GridBagLayout() );
gbc = new GridBagConstraints(0, 0, 1, 1, 50.0, 0.0, A_CENTER, F_DX, IN_0, 0, 0);
add(new JButton("test1"), gbc);
gbc = new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, A_CENTER, F_NONE, IN_0, 0, 0);
add(new JButton("test2"), gbc);
gbc = new GridBagConstraints(2, 0, 1, 1, 50.0, 0.0, A_CENTER, F_DX, IN_0, 0, 0);
add(new JButton("test1"), gbc);
Obviously there's a lot more you can do with a GridBag, and you'll need to do some polishing to get exactly what you want to see, but this should get you started.
The fifth parameter in the GBC constructor is a weight for stretching in the x direction. Setting them equal, and forcing the center component not to stretch (F_NONE) does the dirty work.
How about the MigLayout manager? It is not a part of JRE, but is a great layout manager, which can easily produce the layout you require with less code than GridBag. Check out their demo.
Could not resist to post the totally grid bag cartoon... enjoy (:

How the swing's BoxModel works?

Let's say I would like to create a simple calculator. It consists of 3 fields. Text field to show result, field with checkboxes to select system and field with numbers.
What kind of component should I use for each element ?
How can I position elements in my window ?
How can I position elements inside component (ie checkboxes) ?
This is what I'm trying to achieve.
http://img28.imageshack.us/img28/7691/lab8c.jpg
I would use
JTextField for the number-window
JRadioButton for the radio buttons, and
JButton for the buttons.
The layout of the components should be deferred to a so called layout-manager. (Have a look at Using Layout Managers. In this case a GridLayout and/or a GridBagLayout would do fine.
This code should get you started:
import java.awt.*;
import javax.swing.*;
public class FrameTest {
public static void main(String[] args) {
final JFrame f = new JFrame("Frame Test");
JPanel panel = new JPanel(new GridBagLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1.0;
panel.add(new JTextField(), gbc);
JPanel numSysPanel = new JPanel(new GridLayout(1, 3));
numSysPanel.setBorder(BorderFactory.createTitledBorder("Number System"));
numSysPanel.add(new JRadioButton("oct"));
numSysPanel.add(new JRadioButton("dec"));
numSysPanel.add(new JRadioButton("hex"));
panel.add(numSysPanel, gbc);
JPanel buttons = new JPanel(new GridLayout(4, 4, 2, 2));
for (int i = 0; i < 16; i++)
buttons.add(new JButton("" + i));
panel.add(buttons, gbc);
f.setContentPane(panel);
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
First off, you start with determining, which LayoutManager you should use, to arrange your three fields. GridBagLayout will definitely do what you want, but is quite hard to program. You could try to get away with the simpler BorderLayout, which will make your application look odd, while resizing. You can use GroupLayout too. BoxLayout, GridLayout and FlowLayout are not what you want to use. Now you have a lot of options, to lay out you top elements.
Use a JTextField for the result. Use JCheckBox for the checkboxes, which you put insider a JPanel with an etched border (via JPanel.setBorder(BorderFactory.createEtchedBorder())) and a FlowLayout. Don't forget to put the checkboxes in a CheckboxGroup. Last but not least use a JPanel to group the JButtons for the, uhh, buttons. Use a GridLayout (5 rows, 4 columns) to arrange these buttons.

Categories