Component in JScrollView in GridBagLayout drawn too small - java

I've got a custom component, derived from JComponent. I'm placing that into a JScrollPane and that into a container using GridBagLayout. Now if the container gets too small, i.e. has to start displaying scroll bars, the component becomes tiny.
The example below renders as follows after starting the application:
But after resizing the frame a bit, it becomes this:
Here is the code:
import java.awt.*;
import javax.swing.*;
class SO26736343 extends JPanel {
#Override public void paintComponent(Graphics g) {
g.setColor(Color.YELLOW);
g.fillRect(0, 0, getWidth(), getHeight());
}
#Override public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
public static void main(String[] args) {
JFrame frm = new JFrame();
frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container cp = frm.getContentPane();
cp.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.weightx = 1;
gbc.weighty = 1;
gbc.fill = GridBagConstraints.BOTH;
cp.add(new JButton("NW"), gbc);
cp.add(new JButton("N"), gbc);
gbc.gridwidth = GridBagConstraints.REMAINDER;
cp.add(new JButton("NE"), gbc);
gbc.gridwidth = 1;
cp.add(new JButton("W"), gbc);
cp.add(new JScrollPane(new SO26736343()));
gbc.gridwidth = GridBagConstraints.REMAINDER;
cp.add(new JButton("E"), gbc);
gbc.gridwidth = 1;
cp.add(new JButton("SW"), gbc);
cp.add(new JButton("S"), gbc);
cp.add(new JButton("SE"), gbc);
frm.setSize(500, 500);
frm.setVisible(true);
}
}
I executed this on OS X 10.8.5 with Java 1.7.0_25.
I guess there might be something wrong with my component, but I don't know what. Shouldn't the layout make an attempt to display that component as large as possible, even if it can't be displayed at its preferred size?

I think you forgot to set the constraints when you are adding your custom panel and thus the behavior is unpredictable (or at least unexpected):
gbc.gridwidth = 1;
cp.add(new JButton("W"), gbc);
cp.add(new JScrollPane(new SO26736343())); // gbc missing here
If you want this panel fill all available space, then set both weightx and weighty properties to a value greather than 0 and add your panel using this constraint:
gbc.weightx = 1;
gbc.weighty = 1;
cp.add(new JScrollPane(new SO26736343()), gbc);
Screenshots

This sort of problem happens a lot when I use textfields in Swing. I always set the minimum size of the problem component to its preferred size :
myComponent.setMinimumSize(myComponent.getPreferredSize());
You can also set weight and fill on the gbc.
////////////
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.fill = GridBagConstraints.BOTH;
////////////
This prevents, when the scrollbars kick in, the collapsing effect. Most commonly happens in textfields and text areas.
http://blue-walrus.com/2011/04/swing-textfieldtextarea-collapse-on-dialog-resize/

Related

Buttons doesn't fill all available space when I use GridBagLayout in Java

I want to create an application with buttons arrayed into invisible table. The buttons should fill all the available space inside the imaginary cells even when I´ll resize the frame. I´m using Swing, GridBagLayout. I've read some articles and the solution was to add .weightx=1 and .weighty=1. Weightx works perfect and it fill the gaps but weighty doesn't. Buttons don´t extend into height of cell. Is there a problem with my code or is there something to add that solve my problem? Or should I use absolutely another layout?
public class NewClass {
public void NewClass(){
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
frame.add(panel);
GridBagLayout layout = new GridBagLayout();
panel.setLayout(layout);
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.gridx = 0;
gbc.gridy = 0;
JButton B11 = new JButton("11");
panel.add(B11,gbc);
gbc.gridx = 1;
gbc.gridy = 0;
JButton B12 = new JButton("12");
panel.add(B12,gbc);
gbc.gridx = 0;
gbc.gridy = 1;
JButton B21 = new JButton("21");
panel.add(B21,gbc);
gbc.gridx = 1;
gbc.gridy = 1;
JButton B22 = new JButton("22");
panel.add(B22,gbc);
frame.pack();
frame.setSize(800,400);
frame.setVisible(true);
}}
You're using the wrong GridBagConstraints#fill field value, since the value you're using is telling the layout manager to fill the buttons horizontally only.
You need to change
gbc.fill = GridBagConstraints.HORIZONTAL;
to
// gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.fill = GridBagConstraints.BOTH;
if you want the buttons to fill both directions, both horizontally and vertically.

Gridbag layout -> how to stop components from resizing along with the window?

I have a JFframe form in NetBeans 8 / Java 7.
It has a bunch of labels, textboxes, dropdowns, etc.
These are a column on the left size, all staked up on top of each other.
Here's a screenshot:
How can I prevent all those components from sticking to the right and resizing along with the window and at the same time have the preview frame at the far right resize along?
I'm new to Java, and the gridbaglayout was the only I found to align everything properly. I just want the left side to have its components well aligned and not moving around. And I just want the right side, the panel, to resize according to the window resize.
Thank you,
I just want the right side, the panel, to resize according to the window resize.
By default all the columns are divided in equal percentage in each row.
To force the second (right side) column to take the more space, assign it a higher percentage using GridBagConstraints#weightx
gc.weightx = 0.75; // 75%
Don't forget to fill the horizontal space completely using GridBagConstraints#fill
gc.fill = GridBagConstraints.HORIZONTAL;
If you want fixed width for first column then set the preferred size for the left side panel by overriding getPreferredSize() method and assign 100% width to the right side panel.
JPanel leftSidePanel = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(..., ...);
}
}
Have a look at my another post GridBagLayout: How to set fixed column width? that explain it better.
It;s worth reading Swing Tutorial on Solving Common Layout Problems
You need to set the fill constraint to NONE.
Tutorial: How to Use GridBagLayout:
When you add each Component to the panel, it would look something like this (from the tutorial):
JPanel pane = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
//For each component to be added to this container:
//...Create the component...
//...Set instance variables in the GridBagConstraints instance...
pane.add(theComponent, c);
you need to ensure that you call:
c.fill = GridBagConstraints.NONE;
for every constraints object for each Component that you add to the panel that you don't want to stretch horizontally.
If you're resusing the same constraints object for each component, you can simply set it once for all if that's you're desired result.
EDIT:
As some others have pointed out, the OP may want the fields to stretch, but only up to a certain limit (which is still not clear at this point). In that case, you would use a combination of
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0;
as already pointed out. Example:
import java.awt.*;
import javax.swing.*;
public class GridBagDemo implements Runnable
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new GridBagDemo());
}
public void run()
{
// 4 components that all have different widths
JButton btnBrowse = new JButton("Browse");
JTextField txfHeight = new JTextField(4);
JTextField txfWidth = new JTextField(10);
JButton btnMore = new JButton("More PDF Attributes");
// the preview pane?
JTextArea txaPreview = new JTextArea(8, 20);
JScrollPane scrPreview = new JScrollPane(txaPreview);
scrPreview.setVerticalScrollBarPolicy(
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
GridBagConstraints gbc = new GridBagConstraints();
// we'll use these constraints for all components
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.insets = new Insets(2,4,2,4);
JPanel panel = new JPanel(new GridBagLayout());
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridwidth = 1;
gbc.fill = GridBagConstraints.NONE;
gbc.weightx = 0;
panel.add(new JLabel("Source PDF size..."), gbc);
gbc.gridx = 0;
gbc.gridy = 1;
gbc.gridwidth = 2;
gbc.gridheight = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
panel.add(btnBrowse, gbc);
gbc.gridx = 0;
gbc.gridy = 2;
gbc.gridwidth = 1;
gbc.fill = GridBagConstraints.NONE;
gbc.weightx = 0;
panel.add(new JLabel("Height (in inches):"), gbc);
gbc.gridx = 1;
gbc.gridy = 2;
gbc.gridwidth = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
panel.add(txfHeight, gbc);
gbc.gridx = 0;
gbc.gridy = 3;
gbc.gridwidth = 1;
gbc.fill = GridBagConstraints.NONE;
gbc.weightx = 0;
panel.add(new JLabel("Width (in inches):"), gbc);
gbc.gridx = 1;
gbc.gridy = 3;
gbc.gridwidth = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
panel.add(txfWidth, gbc);
gbc.gridx = 0;
gbc.gridy = 4;
gbc.gridwidth = 2;
gbc.fill = GridBagConstraints.HORIZONTAL;
panel.add(btnMore, gbc);
gbc.gridx = 0;
gbc.gridy = 5;
gbc.gridwidth = 2;
gbc.fill = GridBagConstraints.VERTICAL;
gbc.weighty = 1;
panel.add(Box.createVerticalGlue(), gbc);
gbc.gridx = 2;
gbc.gridy = 0;
gbc.gridwidth = 1;
gbc.fill = GridBagConstraints.NONE;
gbc.weightx = 0;
gbc.weighty = 0;
panel.add(new JLabel("Preview"), gbc);
gbc.gridx = 2;
gbc.gridy = 1;
gbc.gridwidth = 1;
gbc.gridheight = 8; // some number that's > the number of entry rows
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1;
gbc.weighty = 1;
panel.add(scrPreview, gbc);
JFrame frame = new JFrame("GrigBag Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new JScrollPane(panel), BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
the gridbaglayout was the only I found to align everything properly.
The MigLayout manager can do that easily. It also provides much better portability.
Notice the usage of related gaps (r), dialog insets (dialog) and logical pixels (lp).
These units are translated to pixels accordingly. On the other hand, GridbagLayout
sets spaces directly in pixels which is inadequate, e.g. changing font or resolution
will affect the layout.
See to following code example:
package com.zetcode;
import java.awt.EventQueue;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import net.miginfocom.swing.MigLayout;
public class MigLayoutPreview2 extends JFrame {
public MigLayoutPreview2() {
initUI();
setTitle("Design preview");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
private void initUI() {
JPanel pnl = new JPanel(new MigLayout("ins dialog, wrap"));
pnl.add(new JLabel("Source PDF file..."), "pad 0 -5lp 0 0");
pnl.add(new JButton("Browse"), "growx");
pnl.add(new JLabel("Height (inches):"), "sgx, split 2");
pnl.add(new JTextField(10), "growx");
pnl.add(new JLabel("Width (inches):"), "sgx, split 2");
pnl.add(new JTextField(10), "growx");
pnl.add(new JButton("More PDF attributes"), "growx");
pnl.add(new JSeparator(), "pad 0 -5lp 0 0, gaptop r, growx");
pnl.add(new JLabel("Set bounding box..."), "pad 0 -5lp 0 0");
pnl.add(new JComboBox(), "growx");
pnl.add(new JSeparator(), "pad 0 -5lp 0 0, gaptop r, growx");
pnl.add(new JLabel("Sheet size..."), "pad 0 -5lp 0 0");
pnl.add(new JComboBox(), "growx");
pnl.add(new JLabel("Height (inches):"), "sgx, split 2");
pnl.add(new JTextField(10), "growx");
pnl.add(new JLabel("Width (inches):"), "sgx, split 2");
pnl.add(new JTextField(10), "growx");
pnl.add(new JSeparator(), "pad 0 -5lp 0 0, gaptop r, growx");
JPanel rpnl = new JPanel();
rpnl.setBorder(BorderFactory.createEtchedBorder());
pnl.add(rpnl, "cell 2 0, w 90, spany, pushx, grow");
add(pnl);
pack();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
MigLayoutPreview2 ex = new MigLayoutPreview2();
ex.setVisible(true);
}
});
}
}
I have reproduced part of your screenshot and have also kept the indents.
Horizontal separators do not stretch completly, since I believe this is not
optimal design. The design is also improved by eliminating the huge spaces
between labels and text fields.

Setting JButton below TextArea using GridBagLayout

I have a TabbedPane inside of which there are Panels.
I am dealing now with the first panel.
Inside this panel there should be another small panel on the left(I just placed a textfield instead for reference) a textarea in the center and below it a row of buttons. But the buttons are placed far too low below from the textarea. Besides, if I resize the frame, the textarea just goes away, vanishes. The textfield is set ok, top left, the textarea more or less yes in the center, but it should not go away when resizing (it would make a weird effect for the user).
I have tried all variants south, west, whatever, no changes or it goes up too far anyways.
I have read somewhat similar questions but I dont see how their answers solve my case.
So, here is the code:
super("Proyecto");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(1200, 800);
/* 1. CREATE PANEL*/
/*MAIN PANEL BOOK READER*/
JPanel panelbookreader = new JPanel();
/*CREATE TEXTAREA*/
JTextArea areatextobookreader = new JTextArea(20, 80);
/* 2. ADD THAT COMPONENT TO ITS PARENT*/
panelbookreader.add(areatextobookreader);
/* 3. SET A LAYOUT FOR THE PANEL THAT WILL ORGANIZE COMPONENTS INSIDE*/
panelbookreader.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
JTextField hold = new JTextField(20);
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridwidth = 1;
gbc.gridheight = 1;
panelbookreader.add(hold, gbc);
//TEXT AREA
gbc.gridx = 1;
gbc.gridy = 1;
gbc.gridwidth = 0;
gbc.gridheight = 1;
gbc.fill = GridBagConstraints.CENTER;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
panelbookreader.add(areatextobookreader, gbc);
//BUTTONS
gbc.gridx = 1;
gbc.gridy = 2;
gbc.gridwidth = 1;
gbc.gridheight = 1;
gbc.fill = GridBagConstraints.SOUTH;
gbc.weightx = 0.0;
gbc.weighty = 0.0;
panelbookreader.add(openbook, gbc);
/*ADD THE PARENT TO ITS PARENT OR TO GRANPARENT OF COMPONENT*/
JTabbedPane tabulado = new JTabbedPane();
tabulado.addTab("BOOK READER",panelbookreader);
Your weightx for JTextArea is 1.0 which is fine.
But when you specify weighty also as 1.0, then there is no space for JButton. Make some changes in weighty of textarea and also specify weighty for jbutton.

Placing buttons in a specified location using swing in java

I am trying to learn how to make JAVA programs and I am working with Swing. I am trying to place a button in the top left corner of the window and it keeps going to the top center.
public void createGUI(){
JFrame frame = new JFrame("My Project");
frame.setDefaultCloseOperation(3);
frame.setSize(400, 350);
frame.setVisible(true);
JPanel panel = new JPanel();
frame.add(panel);
addButtonGUI(panel, new JButton(), "test", 1, 1);
}
public void addButtonGUI(JPanel panel, JButton button, String text, int x, int y){
GridBagConstraints gbc = new GridBagConstraints();
button.setText(text);
button.setEnabled(true);
gbc.gridx = x;
gbc.gridy = y;
gbc.gridwidth = 2;
gbc.weightx = 1.0D;
gbc.fill = 2;
panel.add(button, gbc);
}
What am I doing wrong or is there a better way to do this?
Please help
You need to set the layout of the JPanel to GridBagLayout to use GridBagConstraints:
JPanel panel = new JPanel(new GridBagLayout());
Also as you only have one effective 'cell' you need to use an anchor and set weighty for the JButton to allow movement in the Y-axis.
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.weighty = 1.0;
Also I would set the fill setting to NONE:
gbc.fill = GridBagConstraints.NONE;
so that the button does not occupy the full width of the panel. (2 = HORIZONTAL fill).
instead of
addButtonGUI(panel, new JButton(), "test", 1, 1);
}
what would happen if you used
addButtonGUI(panel, new JButton(), "test", 0, 0);
}

JScrollPanes inside GridBagLayout gets resized randomly

Here is a tough one for you guys :)
Basically I have a GridBagLayout with 2 columns : a list wrapped in a scrollpane in each one. The scrollpanes are stretched in BOTH direction.
If I progressively reduce the height of this panel (by dragging the window's edge), I see "random" resizing happening on the scrollpanes:
second one's width gets reduced when first's Hscroll bar appears
then, second one's width gets shrinked again for no reason...
If i don't wrap my components, don't get this behavior.
And if you replace the right hand list with a tree, it will behaves differently:
shrinking the window's height bellow 380-ich px, the tree gets resized...
If i don't wrap my components, the tree gets resized anyway if you keep resizing the window !
Do you guys have any idea what's going on ???
PS: the actual layout i am trying to build is more complex than this example. In the mean time i use SpringLayout to do what i want but it requires to much (not so beautiful) things to setup
protected static ListModel newListModel(int n) {
DefaultListModel lm = new DefaultListModel();
for (int i = 0; i < n; ++i)
lm.addElement("AAA");
return lm;
}
protected static JComponent createContentPane() {
JPanel pane = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.CENTER;
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.gridy = 0;
gbc.gridx = 0;
pane.add(new JScrollPane(new JList(newListModel(12))), gbc);
++gbc.gridx;
pane.add(new JScrollPane(new JList(newListModel(4))), gbc);
return pane;
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.getContentPane().add(createContentPane());
f.setSize(800, 400);
f.setLocationRelativeTo(null);
f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
f.setVisible(true);
}
I have an application with several ScrollPanes in a GridBagLayout, and they also exhibit sudden resizes when I resize the window. It seems that a jump occurs when the actual size of the ScrollPane steps over its "preferred size". I have found a workaround: set the preferred size to 1x1 pixels. If the component has positive weight and stretches BOTH, it will still occupy the whole cell, but will not jump. If you need several cells to resize in different proportions, you can set preferred size of another one to, say, 2x1 pixels.
this is basic principles of GridBagLayout, you forgot for define anchor, then you can be able to fix placed JComponent to the rellative Point, and I think that GridBagLayout complicated your GUI, this LayoutManager is better use for placing lots of JComponents to the one container,(without using nested layout)
for example
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
public class BorderPanels extends JFrame {
private static final long serialVersionUID = 1L;
public BorderPanels() {
setLayout(new GridBagLayout());// set LayoutManager
GridBagConstraints gbc = new GridBagConstraints();
JPanel panel1 = new JPanel();
Border eBorder = BorderFactory.createEtchedBorder();
panel1.setBorder(BorderFactory.createTitledBorder(eBorder, "20pct"));
gbc.gridx = gbc.gridy = 0;
gbc.gridwidth = gbc.gridheight = 1;
gbc.fill = GridBagConstraints.BOTH;
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.weightx = gbc.weighty = 20;
add(panel1, gbc); // add compoenet to the COntentPane
JPanel panel2 = new JPanel();
panel2.setBorder(BorderFactory.createTitledBorder(eBorder, "60pct"));
gbc.gridy = 1;
gbc.weightx = gbc.weighty = 60;
//gbc.insets = new Insets(2, 2, 2, 2);
add(panel2, gbc); // add component to the COntentPane
JPanel panel3 = new JPanel();
panel3.setBorder(BorderFactory.createTitledBorder(eBorder, "20pct"));
gbc.gridy = 2;
gbc.weightx = gbc.weighty = 20;
gbc.insets = new Insets(2, 2, 2, 2);
add(panel3, gbc);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // important
pack();
setVisible(true); // important
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() { // important
public void run() {
BorderPanels borderPanels = new BorderPanels();
}
});
}
}
to avoiding against to complicating simple things
use GridLayout (all JComponents have got same Dimmension on the screen)
use BoxLayout or BorderLayout

Categories