Gridbag Layout, Insets or anchor won't take effect - java

Okay, so I need your help guys. I don't know what I missed but the insets and anchor is not taking effect even though I've set the layout to GridBag.
I need to put the logout button just above the tabbedpane and position the logout button on the upper right hand corner. In other words, tabbed pane on position gridx = 0, gridy = 1; and logout Button on position gridx = 0, gridy = 0;
Also, the myaccount button, leftpanel and rightpanel which are inside the home panel, won't get the insets i applied.
What am I missing. Please help because I'm new to this layout.
TopPanel.java
package MainComponents;
import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.border.Border;
import MainTab_TabbedPane.TopTabbedPane;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
public class TopPanel extends JPanel {
//DECLARATION
JButton logOutButton = new JButton("Logout");
TopTabbedPane topTabbedPane = new TopTabbedPane();
private final Border myLineBorder = BorderFactory.createLineBorder(Color.BLACK, 2);
//CONSTRUCTOR
public TopPanel(){
setPanelInitialProperties();
addComponents();
}
//METHODS
private void setPanelInitialProperties(){
setLayout(new GridBagLayout());
setBorder(myLineBorder); //sets a Line Border for this panel
}
private void addComponents(){
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 1;
this.add(topTabbedPane); //adds TabbedPane holding Home, Administration... to this Top Panel
gbc.gridx = 0;
gbc.gridy = 0;
this.add(logOutButton);
}
}
HomeTopPanel.java
package HomeTab;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.border.Border;
public class HomeTopPanel extends JPanel {
private final JButton MyAccountButton = new JButton("My Account");
private final JPanel leftPanel = new JPanel(new GridBagLayout());
private final JPanel rightPanel = new JPanel(new GridBagLayout());
private final Border leftPanelLineBorder = BorderFactory.createLineBorder(Color.BLACK, 2);
private final Border rightPanelLineBorder = BorderFactory.createLineBorder(Color.BLACK, 2);
//CONSTRUCTOR
public HomeTopPanel(){
constructMyAccountButton();
constructPanels();
setLeftRightPanelBorders();
this.setLayout(new GridBagLayout());
}
private void constructMyAccountButton(){
GridBagConstraints MyAccountButton_gbc = new GridBagConstraints();
MyAccountButton_gbc.gridx = 0; MyAccountButton_gbc.gridy = 0;
MyAccountButton_gbc.anchor = GridBagConstraints.NORTHWEST;
this.add(MyAccountButton);
}
private void constructPanels(){
GridBagConstraints leftPanelgbc = new GridBagConstraints();
GridBagConstraints rightPanelgbc = new GridBagConstraints();
leftPanelgbc.insets = new Insets(3,3,3,3);
leftPanelgbc.gridx = 1; leftPanelgbc.gridy = 0;
leftPanel.setPreferredSize(new Dimension(300, 500));
this.add(leftPanel);
rightPanelgbc.insets = new Insets(3,3,3,3);
rightPanelgbc.gridx = 2; leftPanelgbc.gridy = 0;
rightPanel.setPreferredSize(new Dimension(300, 500));
this.add(rightPanel);
}
private void setLeftRightPanelBorders(){
leftPanel.setBorder(leftPanelLineBorder);
rightPanel.setBorder(rightPanelLineBorder);
this.setBorder(leftPanelLineBorder);
}
}
Thanks in advanced. I'm sure there's something I missed but I don't know.
INSETS won't apply. =( ??
UPDATE:
I added the insets with the following code:
private void constructPanels(){
GridBagConstraints gbc2 = new GridBagConstraints();
gbc2.gridx = 1; gbc2.gridy = 0;
gbc2.insets = new Insets(5, 5, 5, 5);
leftPanel.setPreferredSize(new Dimension(250, 300));
this.add(leftPanel,gbc2);
gbc2.gridx = 2; gbc2.gridy = 0;
gbc2.insets = new Insets(5, 5, 5, 5);
rightPanel.setPreferredSize(new Dimension(300, 500));
this.add(rightPanel,gbc2);
}
but still not getting any inset of 5.

Apply the constraints when adding components
add(topTabbedPane, gbc);

GridBagConstraints MyAccountButton_gbc = new GridBagConstraints();
Variable names should NOT start with an upper case character. Most of your other names are correct. Then is no reason to be sloppy. Follow the Java conventions.
constructMyAccountButton();
constructPanels();
setLeftRightPanelBorders();
this.setLayout(new GridBagLayout());
The layout must be set BEFORE you add components to the panel.
GridBagConstraints MyAccountButton_gbc = new GridBagConstraints();
MyAccountButton_gbc.gridx = 0; MyAccountButton_gbc.gridy = 0;
MyAccountButton_gbc.anchor = GridBagConstraints.NORTHWEST;
//this.add(MyAccountButton); // where is the constraint?
this.add(MyAccountButton, myAccountButton_gbc);
You actually have to use the constraint.

Related

GridBagLayout with glue : no fixed row height

I would like to create a panel, to which I can dynamically add sub-panels with fixed height. I tried using a glue component, but it does not work. I would like to achieve that the sub-panels are visible at the top of the gridbaglayout. Side problem is that when I keep adding sub-panels, they start to overlap because the JScrollPane isn't adjusting. However, when I resize the frame, both problems are solved.
At this moment I don't see where I went wrong. Why does the glue component not take up the vertical space to push the side panels to the top?
This is my SSCCE code:
import javax.swing.*;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.awt.GridLayout;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import jrdb.data.ProcessingCommand;
public class ProcessingPipelineBuilderSSCCE extends JFrame {
/**
*
*/
private static final long serialVersionUID = 2413084448601918744L;
private JPanel interiorPanel = null;
private GridBagConstraints gbc = null;
private Component glue = null;
public ProcessingPipelineBuilderSSCCE() {
super("SSCCE");
this.getContentPane().setLayout(new BorderLayout());
gbc = new GridBagConstraints();
gbc.insets = new Insets(5, 5, 0, 5);
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.anchor = GridBagConstraints.PAGE_START;
JPanel pipelineBuilder = new JPanel();
pipelineBuilder.setLayout(new GridLayout(0, 1, 0, 0));
interiorPanel = new JPanel(new GridBagLayout());
interiorPanel.setBorder(BorderFactory.createLineBorder(Color.red));
JScrollPane scrollPane = new JScrollPane(interiorPanel);
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setPreferredSize(new Dimension(500,300));
pipelineBuilder.add(scrollPane);
JButton btnNew = new JButton("Add new panel");
btnNew.setPreferredSize(new Dimension(500, 30));
btnNew.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (glue!=null) {
interiorPanel.remove(glue);
} else {
glue = Box.createGlue();
}
gbc.gridy = gbc.gridy + 1;
interiorPanel.add(new PipelineStep(gbc.gridy),gbc);
interiorPanel.add(glue,gbc);
interiorPanel.validate();
interiorPanel.repaint();
}
});
this.getContentPane().add(btnNew, BorderLayout.PAGE_START);
this.getContentPane().add(pipelineBuilder,BorderLayout.CENTER);
}
public class PipelineStep extends JPanel {
int number;
public PipelineStep (int n) {
super();
JOptionPane.showMessageDialog(interiorPanel, "adding new panel");
this.number = n;
this.setLayout(new FlowLayout());
JLabel lbl = new JLabel(new Integer(this.number).toString());
lbl.setPreferredSize(new Dimension(45,45));
lbl.setFont(lbl.getFont().deriveFont(26));
this.add(lbl);
this.setPreferredSize(new Dimension(450, 50));
this.setBorder(BorderFactory.createLineBorder(Color.green));
}
}
public static void main (String args[]) {
ProcessingPipelineBuilderSSCCE frame = new ProcessingPipelineBuilderSSCCE();
frame.pack();
frame.setVisible(true);
}
}
Why does the glue component not take up the vertical space to push the side panels to the top?
The "glue" component only has meaning when used with the BoxLayout. It has no effect with the GridBagLayout.
So my suggestion is to forget about the GridBagLayout and use the BoxLayout.
The easiest way to do this is to convert "interiorPanel" to use a vertical Box and just add your PipelineStep instances to this panel.
Try this. However, you will notice that the panels will still increase in size until the scroll pane is full, at which time you will see scrollbars appear. This is because the BoxLayout will resize components up to the maximum size of the component. So to prevent this resizing you could override the getMaximumSize() method of your PipelineStep class:
#Override
public Dimension getMaximumSize()
{
return getPreferredSize();
}
Or, another option is to use a "wrapper" panel for your "interiorPanel". Something like:
JPanel wrapper = new JPanel( new BorderLayout() );
wrapper.add(interiorPanel, BorderLayout.PAGE_START);
//JScrollPane scrollPane = new JScrollPane(interiorPanel);
JScrollPane scrollPane = new JScrollPane(wrapper);
BorderLayout.PAGE_START respects the preferred height of the component added to it so the "interiorPanel" will always be displayed at it preferred height and scrollbars will appear when the viewport of the scroll pane is full.
I modified you code using the "wrapper" approach.
import javax.swing.*;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.awt.GridLayout;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
//import jrdb.data.ProcessingCommand;
public class SSCCE1 extends JFrame {
/**
*
*/
private static final long serialVersionUID = 2413084448601918744L;
// private JPanel interiorPanel = null;
private Box interiorPanel = null;
private GridBagConstraints gbc = null;
private Component glue = null;
public SSCCE1() {
super("SSCCE");
this.getContentPane().setLayout(new BorderLayout());
gbc = new GridBagConstraints();
//gbc.insets = new Insets(5, 5, 0, 5);
//gbc.fill = GridBagConstraints.HORIZONTAL;
//gbc.gridx = 0;
//gbc.gridy = 0;
//gbc.weightx = 1.0;
//gbc.weighty = 1.0;
//gbc.anchor = GridBagConstraints.PAGE_START;
JPanel pipelineBuilder = new JPanel();
pipelineBuilder.setLayout(new GridLayout(0, 1, 0, 0));
// interiorPanel = new JPanel(new GridBagLayout());
interiorPanel = Box.createVerticalBox();
interiorPanel.setBorder(BorderFactory.createLineBorder(Color.red));
JPanel wrapper = new JPanel( new BorderLayout() );
wrapper.add(interiorPanel, BorderLayout.PAGE_START);
// JScrollPane scrollPane = new JScrollPane(interiorPanel);
JScrollPane scrollPane = new JScrollPane(wrapper);
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setPreferredSize(new Dimension(500,300));
pipelineBuilder.add(scrollPane);
JButton btnNew = new JButton("Add new panel");
btnNew.setPreferredSize(new Dimension(500, 30));
btnNew.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// if (glue!=null) {
// interiorPanel.remove(glue);
// } else {
// glue = Box.createGlue();
// }
gbc.gridy = gbc.gridy + 1;
// interiorPanel.add(new PipelineStep(gbc.gridy),gbc);
interiorPanel.add(new PipelineStep(gbc.gridy),gbc);
// interiorPanel.add(glue,gbc);
// interiorPanel.validate();
interiorPanel.revalidate();
interiorPanel.repaint();
}
});
this.getContentPane().add(btnNew, BorderLayout.PAGE_START);
this.getContentPane().add(pipelineBuilder,BorderLayout.CENTER);
}
public class PipelineStep extends JPanel {
int number;
public PipelineStep (int n) {
super();
JOptionPane.showMessageDialog(interiorPanel, "adding new panel");
this.number = n;
this.setLayout(new FlowLayout());
JLabel lbl = new JLabel(new Integer(this.number).toString());
lbl.setPreferredSize(new Dimension(45,45));
lbl.setFont(lbl.getFont().deriveFont(26));
this.add(lbl);
this.setPreferredSize(new Dimension(450, 50));
this.setBorder(BorderFactory.createLineBorder(Color.green));
}
}
public static void main (String args[]) {
SSCCE1 frame = new SSCCE1();
frame.pack();
frame.setVisible(true);
}
}

java GUI layout suggestion

public class AFS {
public JPanel afs(final Fields input){
JPanel titlePanel = new JPanel();
//Title fields
JLabel afs = new JLabel("Statement", Label.LEFT);
Label mm = new Label("month ", Label.LEFT);
Label my = new Label("Year ", Label.LEFT);
//first line
titlePanel.add(afs);
titlePanel.add(mm);
titlePanel.add(input.MENTRY);
titlePanel.add(my);
titlePanel.add(input.YENTRY);
titlePanel.setPreferredSize(null);
//Left Panels
JPanel sb = new JPanel();
JPanel entry = new JPanel();
entry.setLayout(new BoxLayout(entry, BoxLayout.Y_AXIS));
entry.setAlignmentX(Component.LEFT_ALIGNMENT);
entry.add(new Label("Service "));
entry.add(input.s);
entry.add(new Label("Amount "));
entry.add(input.a);
entry.add(new Label("Counter "));
entry.add(input.o);
entry.add(new Label("Division "));
entry.add(input.d);
sb.add(entry);
JPanel holderPanel = new JPanel();
holderPanel.setLayout(new BoxLayout(holderPanel, BoxLayout.Y_AXIS));
holderPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
holderPanel.add(titlePanel);
holderPanel.add(sb);
JButton start = new JButton("Save Current");
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
ScriptAction action = new ScriptAction();
action.saveAll(input,1);
}
});
holderPanel.add(start);
return holderPanel;
}
I have a short version of what looks like above code.
The current layout looks like this:
But I want the layout look like (paint edited).
I have tried swap using gridLayout for the entry and it will display 2 rows but gridlayout will still align everything in the center (include the title and the header). Furthermore the button span would be across the entire bottom section. I was wondering if there are any suggested way to do this?
You would need to use a combination of layout managers to achieve the desired output:
Before resize / After resize
In this case there are 3 main parts:
Top pane (Uses Box to align some text on the left and some on the right)
Middle pane (Uses GridBagLayout to position the components as in the image, maybe GridLayout with proper insets might work as well)
Bottom pane (Uses default JPanel's layout: FlowLayout)
The top pane uses 2 JPanels as well, the first one for the label Statement alone and other with FlowLayout aligned to the right for the other 4 components, as per this answer BoxLayout does not respect the preferred size of our JTextFields. So a workaround is to wrap them inside another JPanel and then wrap that JPanel along with the Statement label.
A similar problem arises with the middle pane, which needs to use 2 JPanels: One for the fields wrapped inside another bigger one which holds it and the JButton at the bottom (Save Current). We could achieve a similar output by adding the JButton with a gridx = 2 and gridy = 2 with the counter and division label and fields on gridx = 3 and gridx = 4 respectively (instead of 2 & 3) but we would then need to add gbc.insets to add insets to the top and bottom with high values as well... It's up to you which one to use :)
The code that produces the above outputs is the following:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class FormSample {
private JFrame frame;
private JPanel topRightPane;
private JPanel centerPane;
private JPanel centerWithButtonPane;
private JPanel buttonsPane;
private JTextField monthField;
private JTextField yearField;
private JTextField serviceField;
private JTextField amountField;
private JTextField counterField;
private JTextField divisionField;
private static final int LEFT_MARGIN = 50; //Increase / Decrease to add extra space between components
private static final int RIGHT_MARGIN = LEFT_MARGIN;
//Change insets accordingly to add extra space between components (top, left, bottom, right)
private static final Insets leftInsets = new Insets(0, LEFT_MARGIN, 0, 0);
private static final Insets rightInsets = new Insets(0, 0, 0, RIGHT_MARGIN);
private static final Insets defaultInsets = new Insets(0, 0, 0, 0);
private JButton saveCurrentButton;
private JButton saveAllButton;
private JButton resetButton;
public static void main(String[] args) {
SwingUtilities.invokeLater(new FormSample()::createAndShowGui);
}
private void createAndShowGui() {
frame = new JFrame(getClass().getSimpleName());
monthField = new JTextField(10);
yearField = new JTextField(10);
serviceField = new JTextField(10);
amountField = new JTextField(10);
counterField = new JTextField(10);
divisionField = new JTextField(10);
saveCurrentButton = new JButton("Save Current");
saveAllButton = new JButton("Save all");
resetButton = new JButton("Reset");
buttonsPane = new JPanel();
topRightPane = new JPanel();
topRightPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
topRightPane.add(new JLabel("Month"));
topRightPane.add(monthField);
topRightPane.add(new JLabel("Year"));
topRightPane.add(yearField);
centerWithButtonPane = new JPanel();
centerWithButtonPane.setLayout(new BoxLayout(centerWithButtonPane, BoxLayout.PAGE_AXIS));
Box box = Box.createHorizontalBox();
box.add(new JLabel("Statement"));
box.add(Box.createHorizontalGlue());
box.add(topRightPane);
centerPane = new JPanel();
centerPane.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = defaultInsets;
centerPane.add(new JLabel("Service"), gbc);
gbc.gridx = 1;
gbc.insets = rightInsets;
centerPane.add(serviceField, gbc);
gbc.gridx = 2;
gbc.insets = leftInsets;
centerPane.add(new JLabel("Counter"), gbc);
gbc.gridx = 3;
gbc.insets = defaultInsets;
centerPane.add(counterField, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
gbc.insets = defaultInsets;
centerPane.add(new JLabel("Amount"), gbc);
gbc.gridx = 1;
gbc.insets = rightInsets;
centerPane.add(amountField, gbc);
gbc.gridx = 2;
gbc.insets = leftInsets;
centerPane.add(new JLabel("Division"), gbc);
gbc.gridx = 3;
gbc.insets = defaultInsets;
centerPane.add(divisionField, gbc);
saveCurrentButton.setAlignmentX(Component.CENTER_ALIGNMENT); //Force centered alignment for our JButton
centerWithButtonPane.add(centerPane);
centerWithButtonPane.add(saveCurrentButton);
buttonsPane.add(saveAllButton);
buttonsPane.add(resetButton);
frame.add(box, BorderLayout.NORTH);
frame.add(centerWithButtonPane, BorderLayout.CENTER);
frame.add(buttonsPane, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Also please follow the advices given by #SergiyMedvynskyy about not mixing AWT and Swing components (i.e. JTextField with TextField) and only use Swing components as AWT ones are buggy.

Retain GridBagLayout component order?

I have problems with GridBagLayout. I have to replace a component but after inserting the new one the positions change. See the following code as example.
At the start it is CYAN and YELLOW (from left to the right). After replacing it is YELLOW and RED. My desired result is RED and YELLOW. How can I fix this (with GridBagLayout)?
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GBLTest extends JFrame
{
public static void main(String [] args)
{
new GBLTest();
}
JPanel panelA;
JPanel panelB;
JPanel panelAReplacement;
GBLTest()
{
this.setLayout(new GridBagLayout());
GridBagConstraints cons = new GridBagConstraints();
cons.weightx = 1.0;
cons.weighty = 1.0;
cons.fill = GridBagConstraints.BOTH;
panelA = new JPanel();
panelA.setBackground(Color.CYAN);
panelB = new JPanel();
panelB.setBackground(Color.YELLOW);
panelAReplacement = new JPanel();
panelAReplacement.setBackground(Color.RED);
cons.anchor = GridBagConstraints.EAST;
this.add(panelA, cons);
cons.anchor = GridBagConstraints.WEST;
this.add(panelB, cons);
GridBagConstraints oldCons = ((GridBagLayout) this.getContentPane().getLayout()).getConstraints(panelA);
this.remove(panelA);
this.add(panelAReplacement, oldCons);
this.setSize(new Dimension(200, 200));
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
}
I think you are not using the correct Layout for this pourpose.
You should use BorderLayout instead GridBagLayout. Or use the gridx and gridy properties to set the cell where each panel should be allocated.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GBLTest extends JFrame
{
public static void main(String [] args)
{
new GBLTest();
}
JPanel panelA;
JPanel panelB;
JPanel panelAReplacement;
GBLTest()
{
this.setLayout(new GridBagLayout());
GridBagConstraints consA = new GridBagConstraints();
consA.weightx = 1.0;
consA.weighty = 1.0;
consA.fill = GridBagConstraints.BOTH;
consA.gridx = 0;
consA.gridy = 0;
GridBagConstraints consB = new GridBagConstraints();
consB.weightx = 1.0;
consB.weighty = 1.0;
consB.fill = GridBagConstraints.BOTH;
consB.gridx = 1;
consB.gridy = 0;
panelA = new JPanel();
panelA.setBackground(Color.CYAN);
panelB = new JPanel();
panelB.setBackground(Color.YELLOW);
panelAReplacement = new JPanel();
panelAReplacement.setBackground(Color.RED);
consA.anchor = GridBagConstraints.EAST;
this.add(panelA, consA);
consA.anchor = GridBagConstraints.WEST;
this.add(panelB, consB);
GridBagConstraints oldCons = ((GridBagLayout) this.getContentPane().getLayout()).getConstraints(panelA);
this.remove(panelA);
this.add(panelAReplacement, oldCons);
this.setSize(new Dimension(200, 200));
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
}

Alignment issues with BoxLayout

I am making an application for which I am using a BoxLayout. As you can see in the following picture, when the title string is short, it's perfect. But as the string gets longer, the JLabel gets more and more misaligned.
Here's some code that is related to the problem:
JPanel centerPanel = new JPanel();
centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.PAGE_AXIS));
frame.add(centerPanel, BorderLayout.CENTER);
//...
JLabel l = new JLabel(/*...*/);
l.setHorizontalAlignment(SwingConstants.CENTER); //I tried removing and adding
//this but nothing changed
centerPanel.add(l);
Is there something obvious I am missing? Google isn't being helpful with this problem.
In case it's important, the country-label-progress-bar things are just JPanels with FlowLayouts.
SSCCE:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class SSCCE {
public static void main(String[] args) {
final JFrame f = new JFrame("SSCCE");
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.PAGE_AXIS));
final JLabel[] titles = new JLabel[5];
JPanel[] smallPanels = new JPanel[titles.length];
for (int i = 0; i < smallPanels.length; i ++) {
titles[i] = new JLabel(Math.random() < 0.5 ? "foo" : "bar");
p.add(titles[i]);
smallPanels[i] = new JPanel();
smallPanels[i].add(new JLabel("foobar"));
smallPanels[i].add(new JProgressBar());
p.add(smallPanels[i]);
}
f.add(p, BorderLayout.CENTER);
final JTextField tf = new JTextField("foobar");
tf.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
titles[2].setText(tf.getText());
f.repaint();
}
});
f.add(tf, BorderLayout.NORTH);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(600, 600);
f.setVisible(true);
}
}
To operate the SSCCE, type something in the text field and press enter.
Here is an updated version of your SSCCE with a GridBagLayout. Not sure of how you want components to resize when labels or frame size changes but it should not be too hard to manage this.
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JTextField;
public class SSCCE {
public static void main(String[] args) {
final JFrame f = new JFrame("SSCCE");
JPanel p = new JPanel();
p.setLayout(new GridBagLayout());
Insets insets = new Insets(3, 3, 3, 3);
GridBagConstraints gbc1 = new GridBagConstraints();
gbc1.gridwidth = GridBagConstraints.REMAINDER;
gbc1.anchor = GridBagConstraints.CENTER;
gbc1.insets = insets;
GridBagConstraints gbc2 = new GridBagConstraints();
gbc2.anchor = GridBagConstraints.EAST;
gbc2.insets = insets;
GridBagConstraints gbc3 = new GridBagConstraints();
gbc3.weightx = 1.0;
gbc3.fill = GridBagConstraints.HORIZONTAL;
gbc3.gridwidth = GridBagConstraints.REMAINDER;
gbc3.insets = insets;
final JLabel[] titles = new JLabel[5];
Random random = new Random();
for (int i = 0; i < titles.length; i++) {
titles[i] = new JLabel(Math.random() < 0.5 ? "foo" : "bar");
p.add(titles[i], gbc1);
p.add(new JLabel("foobar"), gbc2);
JProgressBar progress = new JProgressBar();
progress.setStringPainted(true);
progress.setString(String.valueOf(random.nextInt(100)));
p.add(progress, gbc3);
}
f.add(p, BorderLayout.CENTER);
final JTextField tf = new JTextField("foobar");
tf.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
titles[2].setText(tf.getText());
f.repaint();
}
});
f.add(tf, BorderLayout.NORTH);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
}
BoxLayout accepting Min, Max and PreferredSize, childs could be resizable from Min to MaxSize
FlowLayout accepting only PreferredSize, rest (Min, MaxSize) is ignored by this LayoutManager, childs aren't resizable
these XxxSize are calculated from PreferredSize came from childs placed into container (JPanel in this case)
(your question) for better help sooner post an SSCCE, short, runnable, compilable, just about your issue

Sizing issue with scrollable JTextField

I have a form with lots of text fields and some of those text fields may contain very long strings. To make it work I made those text fields scrollable using this code:
JScrollPane scroll = new JScrollPane(textField);
scroll.setPreferredSize(new Dimension((int)textField.getPreferredSize().getWidth(), (int)textField.getPreferredSize().getHeight() * 2));
Then I put scroll into my form using GridBagLayout.
Second line in my example is required for scroller to show up. But it has downside. When I resize window to fit whole text in text field, then scroll disapears leaving me with just two times higher then others text field, which looks ridiculous.
How can I make this all work and show me normal size of text field after scroller is hidden?
EDIT:
You may use following as a demo code to reproduce the issue:
import javax.swing.*;
import java.awt.*;
public class ScrollTextDemo extends JFrame{
public ScrollTextDemo(){
super();
this.setPreferredSize(new Dimension(500, 300));
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
JTextField textField = new JTextField("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
textField.setCursor(new Cursor(0));
textField.setEditable(false);
JScrollPane scroll = new JScrollPane(textField);
scroll.setPreferredSize(new Dimension(70, 40) );
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 0.5;
gbc.insets = new Insets(5, 5, 0, 5);
panel.add(scroll,gbc);
//let's add one more text field without scroll bar to compare
JTextField textField2 = new JTextField("abc");
gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 2;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 0.5;
gbc.insets = new Insets(5, 5, 0, 5);
panel.add(textField2,gbc);
this.add(panel);
}
public static void main(String args[]){
ScrollTextDemo demo = new ScrollTextDemo();
demo.pack();
demo.setVisible(true);
}
}
For this , in the absence of a good SSCCE, I think you hadn't provided any constraint that goes for fill, which is used for
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).
So you must add something like this to your GridBagConstraints
constraintsGridBag.fill = GridBagConstraints.HORIZONTAL;
This will only allow it to expand HORIZONTALLY not both ways.
** EDIT : As for the added code **
Never specify setPreferredSize(...) for any component in Swing. Let the Layout Manager you are using, take care for that. Remove all setPreferredSize(...) thingies, will let it remain in normal size upon resizing.
*EDIT 2 : *
Code to tell you what I am saying :
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.*;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
public class GridBagTest extends JFrame
{
private JPanel topPanel;
private JPanel bottomPanel;
public GridBagTest()
{
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
//gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1.0;
gbc.weighty = 0.8;
// Setting TOP PANEL.
topPanel = new JPanel();
topPanel.setLayout(new GridBagLayout());
GridBagConstraints constraintsTopPanel = new GridBagConstraints();
constraintsTopPanel.gridwidth = 2; // Specifies that this component will take two columns.
constraintsTopPanel.gridheight = 1; // specifies that the component will take one row.
/*
* fill with HORIZONTAL, means the component upon resize, will
* only expand along the X-Axis.
*/
constraintsTopPanel.fill = GridBagConstraints.NONE;
constraintsTopPanel.insets = new Insets(5, 5, 5, 5);
constraintsTopPanel.ipadx = 2;
constraintsTopPanel.ipady = 2;
constraintsTopPanel.weightx = 0.3;
constraintsTopPanel.weighty = 0.2;
constraintsTopPanel.gridx = 0;
constraintsTopPanel.gridy = 0;
JTextField tfield1 = new JTextField("kajslkajfkl dsjlafj lksdj akljsd lfkajflkdj lkaj flkdjalk jflkaj lkfdsj salkj flkaj flkja dslkfjal ksjdflka jlfjd aflsdj", 10);
topPanel.add(tfield1, constraintsTopPanel);
constraintsTopPanel.gridx = 2;
constraintsTopPanel.gridy = 0;
final JTextField tfield2 = new JTextField("kajslkajfkl dsjlafj lksdj akljsd lfkajflkdj lkaj flkdjalk jflkaj lkfdsj salkj flkaj flkja dslkfjal ksjdflka jlfjd aflsdj", 10);
topPanel.add(tfield2, constraintsTopPanel);
constraintsTopPanel.gridx = 4;
constraintsTopPanel.gridy = 0;
JTextField tfield3 = new JTextField("kajslkajfkl dsjlafj lksdj akljsd lfkajflkdj lkaj flkdjalk jflkaj lkfdsj salkj flkaj flkja dslkfjal ksjdflka jlfjd aflsdj", 10);
topPanel.add(tfield3, constraintsTopPanel);
topPanel.setBackground(Color.WHITE);
add(topPanel, gbc);
constraintsTopPanel.gridx = 0;
constraintsTopPanel.gridy = 2;
constraintsTopPanel.gridwidth = 6; // Specifies that this component will take two columns.
constraintsTopPanel.gridheight = 1; // specifies that the component will take one row.
JButton button = new JButton("REMOVE");
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
topPanel.remove(tfield2);
topPanel.revalidate();
topPanel.repaint();
}
});
topPanel.add(button, constraintsTopPanel);
//Setting BOTTOM PANEL.
bottomPanel = new JPanel();
bottomPanel.setLayout(new BorderLayout());
bottomPanel.setBackground(Color.DARK_GRAY);
JLabel label3 = new JLabel("I am a new JLABEL for the bottom JPanel", JLabel.CENTER);
label3.setForeground(Color.WHITE);
bottomPanel.add(label3, BorderLayout.CENTER);
gbc.weighty = 0.2;
add(bottomPanel, gbc);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
pack();
setVisible(true);
}
public static void main(String... args)
{
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new GridBagTest();
}
});
}
}
Well the best I've got is looking ugly in code, but does exactly what I need to the textField. Below is changed sample code from initial question. I'd be thankfull for any ideas how to make it better:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
public class ScrollTextDemo extends JFrame{
public ScrollTextDemo(){
super();
this.setPreferredSize(new Dimension(500, 300));
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
JTextField textField = new JTextField("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
textField.setCursor(new Cursor(0));
textField.setEditable(false);
JScrollPane scroll = new JScrollPane(textField, JScrollPane.VERTICAL_SCROLLBAR_NEVER,JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 0.5;
//gbc.ipady = 20;//gives some room for scroll to appear and don't hide text area under the scroll.
gbc.insets = new Insets(5, 5, 0, 5);
panel.add(scroll,gbc);
//let's add one more text field without scroll bar to compare
JTextField textField2 = new JTextField("bbbbbbbb");
gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 2;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 0.5;
gbc.insets = new Insets(5, 5, 0, 5);
panel.add(textField2,gbc);
scroll.addComponentListener( new ScrollTextComponentListener(scroll, textField2));
this.add(panel);
}
public static void main(String args[]){
ScrollTextDemo demo = new ScrollTextDemo();
demo.pack();
demo.setVisible(true);
}
}
class ScrollTextComponentListener implements ComponentListener {
private boolean scrollVisible;
private JScrollPane scroll;
private JComponent compareComponent;
public ScrollTextComponentListener(JScrollPane scroll, JComponent compareComponent) {
this.scroll = scroll;
this.compareComponent = compareComponent;
}
private boolean isScrollVisible() {
return scroll.getHorizontalScrollBar().getModel().getExtent() != scroll.getHorizontalScrollBar().getModel().getMaximum();
}
private void setScrollSize(){
boolean scrollVisible = isScrollVisible();
if (scrollVisible){
scroll.setPreferredSize(new Dimension(compareComponent.getWidth(),compareComponent.getHeight()*2));
//also had to set both min and max sizes, because only preffered size didn't always work
scroll.setMinimumSize(new Dimension(compareComponent.getWidth(),compareComponent.getHeight()*2));
scroll.setMaximumSize(new Dimension(compareComponent.getWidth(),compareComponent.getHeight()*2));
}
else {
scroll.setPreferredSize(new Dimension(compareComponent.getWidth(),compareComponent.getHeight()));
scroll.setMinimumSize(new Dimension(compareComponent.getWidth(),compareComponent.getHeight()));
scroll.setMaximumSize(new Dimension(compareComponent.getWidth(),compareComponent.getHeight()));
}
this.scrollVisible = scrollVisible;
}
#Override
public void componentResized(ComponentEvent e) {
if (isScrollVisible() != scrollVisible) setScrollSize();
}
#Override
public void componentMoved(ComponentEvent e) {
}
#Override
public void componentShown(ComponentEvent e) {
setScrollSize();
}
#Override
public void componentHidden(ComponentEvent e) {
}
}

Categories

Resources