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) {
}
}
Related
Here is a pretty simple layout (code included) where non-uniform column sizes could improve packing.
Is there a way, using a single GridBagLayout, to get the components to fit together nicely?
I thought that using a width of 3 for the top two components, then a width of 5 & 1 for the next two rows would influence the alignment, but I cannot get it to stay flush. My current solution (not included) is to create a sub panel with the red and green panels.
import javax.swing.*;
import java.awt.*;
public class GridBagWrong{
public static void main(String[] args){
JPanel content = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
//create five panels to layout.
JPanel a = new JPanel();
a.setPreferredSize( new Dimension(300, 30) );
a.setBorder( BorderFactory.createLineBorder(Color.BLUE) );
JPanel b = new JPanel();
b.setPreferredSize( new Dimension(300, 30) );
b.setBorder( BorderFactory.createLineBorder(Color.BLUE) );
JPanel c = new JPanel();
c.setPreferredSize( new Dimension(500, 30) );
c.setBorder( BorderFactory.createLineBorder(Color.GREEN) );
JPanel d = new JPanel();
d.setPreferredSize( new Dimension(500, 30) );
d.setBorder( BorderFactory.createLineBorder(Color.GREEN) );
JPanel e = new JPanel();
e.setPreferredSize( new Dimension(100, 60) );
e.setBorder( BorderFactory.createLineBorder(Color.RED) );
//place them in a gridbaglayout.
gbc.gridwidth = 3;
content.add(a, gbc);
gbc.gridx = 3;
content.add(b, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
gbc.gridwidth = 5;
content.add(c, gbc);
gbc.gridy = 2;
content.add(d, gbc);
gbc.gridy = 1;
gbc.gridx = 5;
gbc.gridheight = 2;
gbc.gridwidth = 1;
content.add(e, gbc);
JFrame frame = new JFrame("test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setContentPane( content );
frame.pack();
frame.setVisible(true);
}
}
Following up on my comment from above you can use:
//JPanel content = new JPanel(new GridBagLayout());
GridBagLayout gbl = new GridBagLayout();
int[] columns = new int[6];
Arrays.fill(columns, 100);
gbl.columnWidths = columns;
JPanel content = new JPanel(gbl);
The above code states each of the 6 columns will have a minimum width of 100.
If a component is added to a column with gridwidth = 1, then the preferred size of that component will be used as the width of the column.
So now when you specify gridwidth = 3 it has a meaning because the layout can use either the width of a component added to the columnn or the minimum width to determine the actual size of the component.
For some reason GridBagLayout is adding addition space to it's calculations, but I'm not sure why. At first I thought it was the LineBorder, but when I modified your code to remove the border, it still didn't work...
I don't know where the extra spacing on the right is coming from (it's probably really obvious, but I can't see it)
Sooo, this is one of those moments where I "flip the table" and "rage quite" and instead, "hack it"
Since there seems to be a disconnect between the first and second row, for some reason, I combined the two panels from the first row into a single panel and got rid of all the gridwidths (more or less)
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
//create five panels to layout.
JPanel a = new LayoutPane();
a.setForeground(Color.BLUE);
a.setPreferredSize(new Dimension(300, 30));
JPanel b = new LayoutPane();
b.setPreferredSize(new Dimension(300, 30));
b.setForeground(Color.BLUE);
JPanel c = new LayoutPane();
c.setPreferredSize(new Dimension(500, 30));
c.setForeground(Color.GREEN);
JPanel d = new LayoutPane();
d.setPreferredSize(new Dimension(500, 30));
d.setForeground(Color.GREEN);
JPanel e = new LayoutPane();
e.setPreferredSize(new Dimension(100, 60));
e.setForeground(Color.RED);
JPanel topPane = new JPanel(new GridBagLayout());
//place them in a gridbaglayout.
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
topPane.add(a, gbc);
gbc.gridx++;
topPane.add(b, gbc);
gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
add(topPane, gbc);
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 1;
gbc.anchor = GridBagConstraints.WEST;
add(c, gbc);
gbc.gridy = 2;
add(d, gbc);
gbc = new GridBagConstraints();
gbc.gridy = 1;
gbc.gridx++;
gbc.gridheight = 2;
gbc.anchor = GridBagConstraints.EAST;
add(e, gbc);
}
}
public class LayoutPane extends JPanel {
public LayoutPane() {
setOpaque(false);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(getForeground());
g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
String text = getWidth() + "x" + getHeight();
FontMetrics fm = g2d.getFontMetrics();
int x = (getWidth() - fm.stringWidth(text)) / 2;
int y = ((getHeight() - fm.getHeight()) / 2) + fm.getAscent();
g2d.drawString(text, x, y);
g2d.dispose();
}
}
}
I've seen two other posts on stackoverflow about this and in both, the solutions use setConstraints(myComponent, anotherConstraint) which doesn't even come up as an available method when I try to use it in java.
want to change an Inset in a gridbag layout dynamically
Change the component weight dynamically in GridBagLayout
How else could I change the weightx of a component after a button press?
The actual problem is that I have two components at the bottom of the screen and I need to set one of the components to be the max width of the screen after a button press.
I couldn't get setConstraints() to work..
Then it seems the code was wrong. From the fact the RHS of the red panel neatly aligns with the LHS of the Articuno label I suspect that the grid bag cell containing the red panel does not span more than one column, and currently entirely fills that column.
There could be other reasons, but short a minimal reproducible example I won't speculate further.
Here is a simplified example showing how to do it. Note that it was necessary to call revalidate() before the changes could be seen.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.image.BufferedImage;
public class FullWidthToggle {
private JComponent ui = null;
FullWidthToggle() {
initUI();
}
public final void initUI() {
if (ui != null) {
return;
}
GridBagConstraints gbc = new GridBagConstraints();
GridBagLayout gbl = new GridBagLayout();
ui = new JPanel(gbl);
ui.setBorder(new EmptyBorder(4, 4, 4, 4));
BufferedImage image = new BufferedImage(
160, 20, BufferedImage.TYPE_INT_RGB);
gbc.insets = new Insets(5, 5, 5, 5);
ui.add(new JLabel(new ImageIcon(image)), gbc);
final JCheckBox checkBox = new JCheckBox("Full Width");
gbc.gridx = 1;
gbc.anchor = GridBagConstraints.LINE_START;
ui.add(checkBox, gbc);
final JLabel label = new JLabel("Am I full width?");
label.setBorder(new LineBorder(Color.RED, 2));
gbc.gridx = 0;
gbc.gridy = 1;
gbc.gridwidth = 2;
ui.add(label, gbc);
ActionListener actionListener = (ActionEvent e) -> {
if (checkBox.isSelected()) {
gbc.fill = GridBagConstraints.HORIZONTAL;
} else {
gbc.fill = GridBagConstraints.NONE;
}
gbl.setConstraints(label, gbc);
ui.revalidate(); // <- important!
};
checkBox.addActionListener(actionListener);
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = () -> {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
FullWidthToggle o = new FullWidthToggle();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
};
SwingUtilities.invokeLater(r);
}
}
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.
I have an ItemListener that looks like this:
private class Listener implements ItemListener
{
public void itemStateChanged(ItemEvent e)
{
calculate();
}
}
At the bottom of my calculate() method, I set these labels like this:
subtotalLbl.setText("\t\t\t\t\t\t\t\tSubtotal:\t\t\t\t\t\t\t\t\t " + String.valueOf(determinedSubTotal + priceIncrease) + "\t\t\t\t\t\t\t\t\t");
taxLbl.setText("\t\t\t\t\t\t\t\tTax:\t\t\t\t\t\t\t\t\t " + String.valueOf(determinedTax + priceIncrease) + "\t\t\t\t\t\t\t\t\t");
totalLbl.setText("\t\t\t\t\t\t\tTotal:\t\t\t\t\t\t\t\t\t " + String.valueOf(determinedTotal + priceIncrease) + "\t\t\t\t\t\t\t\t\t");
Then I have an ActionListener that uses the text from the totalLbl for parseDouble
private class BtnClicked implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String input = totalLbl.getText().trim();
Double parsedString = Double.parseDouble(input) * 0.20;
Object src = e.getSource();
if(src == submit)
{
JOptionPane.showMessageDialog(null,"Thank you for your order - the tip will be " + fmt.format(parsedString), "Thank you" , JOptionPane.INFORMATION_MESSAGE);
}
else if(src == cancel)
{
JOptionPane.showMessageDialog(null,"Order was canceled" ,"Order Canceled" , JOptionPane.INFORMATION_MESSAGE);
}
}
Obviously the program is crashing at the line inside of the BtnClicked's actionPerformed method where parseDouble(input) is at, because the totalLbl JLabel has "Total:" in it.. where else would I set this or how would I work around this? The "Total:" is required. (can't use split() )
Here's a screenshot of what the entire JFrame looks like, program crashes when clicking the submit button:
Create two JLables, one which says Total: the other which actually holds the total value.
So your total calculation would look more like...
totalLblText.setText("Total:");
totalLbl.setText(String.valueOf(determinedTotal + priceIncrease));
Then you won't need to care.
You should make better use of your layout managers in order to support the formatting your trying to achieve rather than using formatting characters like \t, these will always end up in a mess
Updated with layout example
This simple example demonstrates how you might use a layout managers (and a technique known as compound layouts) and relieve the need to try and use a single label for displaying more information then it should...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestLayout {
public static void main(String[] args) {
new TestLayout();
}
public TestLayout() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextField numberOfPizzas;
private JCheckBox pepperoni;
private JCheckBox sausage;
private JCheckBox peppers;
private JCheckBox onions;
private JCheckBox mushrooms;
private JCheckBox extracheese;
private JLabel lblSubTotal;
private JLabel lblTax;
private JLabel lblTotal;
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridwidth = 1;
gbc.weightx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
JPanel header = new JPanel();
JPanel extras = new JPanel(new GridBagLayout());
JPanel totals = new JPanel(new GridBagLayout());
add(header, gbc);
gbc.gridy++;
add(extras, gbc);
gbc.gridy++;
add(totals, gbc);
numberOfPizzas = new JTextField(5);
header.add(new JLabel("Number of pizzas"));
header.add(numberOfPizzas);
gbc = new GridBagConstraints();
pepperoni = new JCheckBox("Pepperoni");
sausage = new JCheckBox("Sausage");
peppers = new JCheckBox("Peppers");
onions = new JCheckBox("Onions");
mushrooms = new JCheckBox("mushrooms");
extracheese = new JCheckBox("Extra Cheeses");
JCheckBox left[] = new JCheckBox[] {pepperoni, peppers, mushrooms};
JCheckBox right[] = new JCheckBox[] {sausage, onions, extracheese};
gbc.anchor = GridBagConstraints.WEST;
gbc.gridx = 0;
gbc.gridy = 0;
add(left, extras, 0, 1, gbc);
gbc.gridx = 1;
gbc.gridy = 0;
add(right, extras, 0, 1, gbc);
gbc = new GridBagConstraints();
gbc.weightx = 1;
gbc.gridx = 0;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.EAST;
gbc.insets = new Insets(2, 12, 2, 12);
totals.add(new JLabel("Subtotal:"), gbc);
gbc.gridy++;
totals.add(new JLabel("Tax:"), gbc);
gbc.gridy++;
totals.add(new JLabel("Total:"), gbc);
gbc.weightx = 0;
gbc.gridx = 1;
gbc.gridy = 0;
lblSubTotal = new JLabel("8.0");
lblTax = new JLabel("0.78");
lblTotal = new JLabel("8.78");
totals.add(lblSubTotal, gbc);
gbc.gridy++;
totals.add(lblTax, gbc);
gbc.gridy++;
totals.add(lblTotal, gbc);
}
protected void add(JComponent[] comps, JComponent parent, int deltaX, int deltaY, GridBagConstraints gbc) {
for (JComponent comp : comps) {
parent.add(comp, gbc);
gbc.gridy += deltaY;
gbc.gridx += deltaX;
}
}
}
}
Lots of different ways to do this, the easiest is probably:
String[] parts = totalLbl.getText().split(":");
String input = parts[1].trim();
Double parsedString = Double.parseDouble(input) * 0.20;
you can do this
str = str.replaceAll("\\D+","");
this will delete non digits from the string
so you would want it to be like this
Double parsedString = Double.parseDouble(input.replaceAll("\\D+","")*0.20);
You can use separate widgets for the label and the value. E.g. The total label, create a JLabel object and set the text with static value "Total:", then for the total value, create a JTextField object and set the text with the actual value. When submitting, get the value from the textfield instead of from the label. Don't forget to call setEditable(false) to the textfield because the textfield is meant to display the value only, not to accept input.
Here is my code. When I resize the program the other layouts, it works fine except for the CheckPanel (with GridBagLayout); somehow it became bigger. How can I handle this?
Advance Thanks.
JPanel CheckPanel = new JPanel();
CheckPanel.setBackground(Color.WHITE);
GridBagConstraints gbc_CheckPanel = new GridBagConstraints();
gbc_CheckPanel.gridwidth = 2;
gbc_CheckPanel.fill = GridBagConstraints.BOTH;
gbc_CheckPanel.gridx = 0;
gbc_CheckPanel.gridy = 1;
CenterPanel.add(CheckPanel, gbc_CheckPanel);
CheckPanel.setLayout(new GridLayout(0, 6, 0, 0));
The constraint
gbc_CheckPanel.fill = GridBagConstraints.BOTH;
tells the GridBagLayout to let this component use any available extra space (also depending on its preferred- and maximum size). Using GridBagConstraints.NONE or GridBagConstraints.VERTICAL could solve this, but you still have to decide which component will receive the extra space.
EDIT: Based on the comments, it is still not clear how the other components are inserted, and how the distribution of extra space is specified. In this example, the weighty fields are used to say that the table should receive all extra space. Maybe it helps to identify differences to the original program:
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class CheckboxConstraints
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel centerPanel = new JPanel(new GridBagLayout());
centerPanel.setBackground(Color.RED);
fill(centerPanel);
f.getContentPane().setLayout(new GridLayout(1,1));
f.getContentPane().add(centerPanel);
f.setSize(500, 300);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static void fill(JPanel centerPanel)
{
addSearchBar(centerPanel);
addCheckBoxPanel(centerPanel);
addTable(centerPanel);
}
private static void addSearchBar(JPanel centerPanel)
{
GridBagConstraints gbc = null;
gbc = new GridBagConstraints();
gbc.gridwidth = 1;
gbc.fill = GridBagConstraints.BOTH;
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 0;
gbc.weighty = 0;
centerPanel.add(new JButton("Search"), gbc);
gbc = new GridBagConstraints();
gbc.gridwidth = 1;
gbc.fill = GridBagConstraints.BOTH;
gbc.gridx = 1;
gbc.gridy = 0;
gbc.weightx = 1;
gbc.weighty = 0;
centerPanel.add(new JTextField(), gbc);
}
private static void addCheckBoxPanel(JPanel centerPanel)
{
JPanel checkPanel = new JPanel();
checkPanel.setBackground(Color.WHITE);
GridBagConstraints gbc_CheckPanel = new GridBagConstraints();
gbc_CheckPanel.gridwidth = 2;
gbc_CheckPanel.fill = GridBagConstraints.BOTH;
gbc_CheckPanel.gridx = 0;
gbc_CheckPanel.gridy = 1;
gbc_CheckPanel.weighty = 0;
centerPanel.add(checkPanel, gbc_CheckPanel);
checkPanel.setLayout(new GridLayout(0, 6, 0, 0));
checkPanel.add(new JCheckBox("C0"));
checkPanel.add(new JCheckBox("C1"));
checkPanel.add(new JCheckBox("C2"));
checkPanel.add(new JCheckBox("C3"));
checkPanel.add(new JCheckBox("C4"));
checkPanel.add(new JCheckBox("C5"));
}
private static void addTable(JPanel centerPanel)
{
JTable table = new JTable(new Object[][] {
{"C00", "C01" },
{"C00", "C01" },
}, new Object[]{ "H0", "H1" });
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = 2;
gbc.fill = GridBagConstraints.BOTH;
gbc.gridx = 0;
gbc.gridy = 2;
gbc.weighty = 1.0;
JScrollPane scrollPane = new JScrollPane(table);
centerPanel.add(scrollPane, gbc);
}
}
Please try:
gbc_CheckPanel.fill =GridBagConstraints.HORIZONTAL
and to adjust the space vertically
gbc_CheckPanel.ipady = 20; //Not sure this works in your case but this should fix the resizing issue
Another solution is to add a new JPanel with BorderLayout and insert the panel with JCheckBoxes using the constraint BorderLayout.NORTH and the table with constraint BorderLayout.CENTRE