Variable Layout in Swing

Variable Layout in Swing

MiGLayout has a lot of appeal, but BoxLayout is an alternative.

image

import java.awt.*;
import java.util.List;
import java.util.ArrayList;
import javax.swing.*;

public class BoxTest extends JPanel {

private List<JTextField> fields = new ArrayList<JTextField>();

public BoxTest() {
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
this.add(createPane(3, "One ", Color.red));
this.add(createPane(3, "Two ", Color.green));
this.add(createPane(10, "Three ", Color.blue));
}

private JPanel createPane(int n, String s, Color c) {
JPanel outer = new JPanel();
outer.setLayout(new BoxLayout(outer, BoxLayout.Y_AXIS));
outer.setBorder(BorderFactory.createLineBorder(c, 2));
for (int i = 0; i < n; i++) {
JPanel inner = new JPanel();
inner.setLayout(new BoxLayout(inner, BoxLayout.X_AXIS));
JLabel label = new JLabel(s + i + ":", JLabel.RIGHT);
label.setPreferredSize(new Dimension(80, 32));
inner.add(label);
JTextField tf = new JTextField("Stackoverflow!", 32);
inner.add(tf);
fields.add(tf);
outer.add(inner);
}
return outer;
}

private void display() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JScrollPane jsp = new JScrollPane(this,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
this.validate();
Dimension d = this.getPreferredSize();
d.height /= 2;
jsp.getViewport().setPreferredSize(d);
jsp.getVerticalScrollBar().setUnitIncrement(
this.getPreferredSize().height / fields.size());
f.add(jsp);
f.pack();
f.setVisible(true);
}

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {

@Override
public void run() {
new BoxTest().display();
}
});
}
}

Java Swing: Vertical Layout with fixed width and variable height

OK, I got it to work. I was completely wrong, I thought the JScrollPane was the trouble maker for this issue, but it was the JLabel. If a JLabel contains HTML text, it won't wrap the text automatically, that's why everything got stretched horizontally, if the dialog's width was too little. I found a good solution for this problem here: make a JLabel wrap it's text by setting a max width

Answer 6:

JLabel labelBeingUsed = myLabel;
View view = (View) labelBeingUsed.getClientProperty(BasicHTML.propertyKey);
view.setSize(scrollPane1.getWidth(), 0.0f);
float w = view.getPreferredSpan(View.X_AXIS);
float h = view.getPreferredSpan(View.Y_AXIS);
labelBeingUsed.setSize((int) w, (int) h);

Everytime the dialog is resized, it is necessary to update the width of each HTML containing JLabel to the desired width using the code above.

Thank you very much for all your useful tips.

Resizable Swing layout with buttons arranged according to variable dimensions

For example, by use of a different LayoutManager, a very easy and simple container, takes no more than 15-20 minutes:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

public class ThinLineFrame {
private JFrame frame = new JFrame();
private JScrollPane scrollPane;
private JPanel panel = new JPanel();
private JPanel panelNorth = new JPanel();
private JPanel panelCenter = new JPanel();
private JPanel panelCenterCh1 = new JPanel();
private JPanel panelCenterCh2 = new JPanel();
private JPanel panelCenterCh3 = new JPanel();
private JPanel panelCenterCh4 = new JPanel();
private JPanel panelCenterCh5 = new JPanel();
private JPanel panelSouth = new JPanel();

public ThinLineFrame() {
panelNorth.setBackground(Color.red.darker());
panelNorth.setPreferredSize(new Dimension(80, 30));
//
panelCenter.setBackground(Color.darkGray);
panelCenter.setLayout(new GridLayout(5, 1, 2, 2));
//
panelCenterCh1.setLayout(new BorderLayout());
JButton panelCenterCh1Button = new JButton();
panelCenterCh1.add(panelCenterCh1Button, BorderLayout.CENTER);
//
JButton panelCenterCh2Button1 = new JButton();
JButton panelCenterCh2Button2 = new JButton();
panelCenterCh2.setLayout(new GridLayout(2, 1, 2, 2));
panelCenterCh2.add(panelCenterCh2Button1);
panelCenterCh2.add(panelCenterCh2Button2);
//
JButton panelCenterCh3Button1 = new JButton();
JButton panelCenterCh3Button2 = new JButton();
panelCenterCh3.setLayout(new GridLayout(2, 1, 2, 2));
panelCenterCh3.add(panelCenterCh3Button1);
panelCenterCh3.add(panelCenterCh3Button2);
//
JButton panelCenterCh4Button1 = new JButton();
JButton panelCenterCh4Button2 = new JButton();
panelCenterCh4.setLayout(new GridLayout(2, 1, 2, 2));
panelCenterCh4.add(panelCenterCh4Button1);
panelCenterCh4.add(panelCenterCh4Button2);
//
panelCenterCh5.setLayout(new BorderLayout());
JButton panelCenterCh5Button = new JButton();
panelCenterCh5.add(panelCenterCh5Button, BorderLayout.CENTER);
//
panelCenter.add(panelCenterCh1);
panelCenter.add(panelCenterCh2);
panelCenter.add(panelCenterCh3);
panelCenter.add(panelCenterCh4);
panelCenter.add(panelCenterCh5);
//
panelSouth.setBackground(Color.red.darker());
panelSouth.setPreferredSize(new Dimension(80, 30));
//
panel.setLayout(new BorderLayout(2, 2));
panel.add(panelNorth, BorderLayout.NORTH);
panel.add(panelCenter, BorderLayout.CENTER);
panel.add(panelSouth, BorderLayout.SOUTH);
//
scrollPane = new JScrollPane(panel);
frame.add(scrollPane, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(80, 600));
frame.setLocation(100, 150);
frame.pack();
frame.setVisible(true);
}

public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {

public void run() {
ThinLineFrame dlg = new ThinLineFrame();
}
});
}
}

Layout with fixed height and variable width JButtons

What about something where a GridLayout is nested in a BorderLayout (actually in a JScrollPane)...

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;

import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class Chooser extends JPanel {
private static final String[] BUTTON_TEXTS = { "Hello", "Goodbye",
"Hello Goodbye", "Adios", "This is a long String for WTF" };

public Chooser() {
this.setLayout(new BorderLayout());

JPanel labelPanel = new JPanel();
JLabel label = new JLabel("Choose a file:");
labelPanel.add(label);
labelPanel.setBackground(Color.red);

JPanel buttonPanel = new JPanel(new GridLayout(0, 1));
for (int i = 0; i < BUTTON_TEXTS.length; i++) {
buttonPanel.add(new JButton(BUTTON_TEXTS[i]));
}
buttonPanel.add(Box.createVerticalGlue()); // to pad the bottom if needed
buttonPanel.setBackground(Color.blue);

this.add(labelPanel, BorderLayout.PAGE_START);
this.add(new JScrollPane(buttonPanel), BorderLayout.CENTER);
}

public static void main(String[] args) {
Chooser c = new Chooser();
JFileChooser fileChooser = new JFileChooser();
fileChooser.setAccessory(c);
fileChooser.showOpenDialog(null);
}

}

Example 2 with a simple JList that places its selection in the file chooser:

import java.awt.*;
import java.io.File;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

public class Chooser extends JPanel {
private static final String[] BUTTON_TEXTS = { "Hello", "Goodbye",
"Hello Goodbye", "Adios", "This is a long String for WTF", "Hello",
"Goodbye", "Hello Goodbye", "Adios", "This is a long String for WTF" };

public Chooser(final JFileChooser fileChooser) {
setLayout(new BorderLayout());

JPanel labelPanel = new JPanel();
JLabel label = new JLabel("Choose a file:");
labelPanel.add(label);
labelPanel.setBackground(Color.red);

final JList list = new JList(BUTTON_TEXTS);
list.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
String selectedString = list.getSelectedValue().toString();
fileChooser.setSelectedFile(new File(selectedString));
}
});

add(labelPanel, BorderLayout.PAGE_START);
add(new JScrollPane(list), BorderLayout.CENTER);
}

public static void main(String[] args) {
JFileChooser fileChooser = new JFileChooser();
Chooser c = new Chooser(fileChooser);
fileChooser.setAccessory(c);
fileChooser.showOpenDialog(null);
}

}

Fixed width, variable height in JPanel with flow

Wrap Layout should help.

In Java, is there a way to center a group of buttons with variable size(Using Swing)?

Layouts are a little bit of black magic and trial and error. Very rarely will a single layout achieve exactly what you want, so you often need to resort to compound layouts (using multiple containers and layouts) to get what you want...

Example

So, basically, this is made of a panel, with another panel holding the buttons (and another panel acting as the "pseudo" content to add space)

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

public static void main(String[] args) {
new Test();
}

public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
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();
gbc.gridwidth = GridBagConstraints.REMAINDER;

add(new JLabel("Question"), gbc);
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1;
gbc.weighty = 1;
// This is just to act as some psudo context
add(new FillerPane(), gbc);
gbc.fill = GridBagConstraints.NONE;
gbc.weightx = 0;
gbc.weighty = 0;
add(makeButtonPane(), gbc);
add(new JLabel("Goodratio"), gbc);
}

public JPanel makeButtonPane() {
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.weightx = 1;
panel.add(new JButton("Short"));
panel.add(new JButton("Long, long, long and lobng"));
panel.add(new JButton("In the middle"));
return panel;
}

}

public class FillerPane extends JPanel {

@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}

}

}

"But I want the buttons to be the same size" I hear you ask, sure, change layouts...

Another example

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

public static void main(String[] args) {
new Test();
}

public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
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();
gbc.gridwidth = GridBagConstraints.REMAINDER;

add(new JLabel("Question"), gbc);
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1;
gbc.weighty = 1;
// This is just to act as some psudo context
add(new FillerPane(), gbc);
gbc.fill = GridBagConstraints.NONE;
gbc.weightx = 0;
gbc.weighty = 0;
add(makeButtonPane(), gbc);
add(new JLabel("Goodratio"), gbc);
}

public JPanel makeButtonPane() {
JPanel panel = new JPanel(new GridLayout(1, 0));
panel.add(new JButton("Short"));
panel.add(new JButton("Long, long, long and lobng"));
panel.add(new JButton("In the middle"));
return panel;
}

}

public class FillerPane extends JPanel {

@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}

}

}

You have to look at the layout and think about how each element relates to the others, in terms of what you want them to do, then find the layout managers which are going to help you achieve the end results and combine them together

How do I pass values between cards in Java CardLayout....this time i have given a good example

You somehow have to pass a reference of the second panel to the first one:

Main class:

public class MainPane 
{
public void displayGUI()
{
....
p1 = new Firstcard1(contentPane);
p2 = new SecondCard1(contentPane);

p1.setSecondCard(p2);
....
}
}

First card:

public class Firstcard1 extends javax.swing.JPanel {
....

private SecondCard secondCard;

void setSecondCard(SecondCard secondCard)
{
this.secondCard = secondCard;
}

....

private void LoginActionPerformed(java.awt.event.ActionEvent evt)
{
CardLayout layout = (CardLayout)contentpane.getLayout();
layout.show(contentpane, "Panel 2");
secondCard.getTextField().setText(jTextField1.getText());
}
}

Second card:

public class SecondCard1 extends javax.swing.JPanel 
{
...
JTextField getTextField()
{
return jTextField1;
}
...
}

But when you continue like this, the program will probably become a mess pretty soon. I'd recommend to create these components manually, without using any visual GUI builders.

How to access a CardLayout variable from an outside class?

Do they need to be in separate files? You can make PanelTwo an inner class of lay class. You're getting the error, because the tow variables are not in the scope of the lay class which those are members of. If you did the below, errors would go away.

public class lay {
...
private class PanelTwo {

}
}

EDIT

What you need to do using two separate class files is to create a constructor in the PanelTwo where you take in arguments of your CardLayout and the JPanel from the lay class. Then instantiate the PanelTwo with those two arguments.

Try this out. I passed the CardLayout and the JPanel to a constructor of PanelTwo. Works fine.

import java.awt.CardLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class lay {

JFrame frame;
JPanel panelCont;
JPanel panelOne;
JButton buttonOne;
CardLayout cards;

PanelTwo panelTwo;

public lay() {
frame = new JFrame("Start");
panelCont = new JPanel();
panelOne = new JPanel();
cards = new CardLayout();
panelTwo = new PanelTwo(cards, panelCont);
buttonOne = new JButton("Got to two");

panelCont.setLayout(cards);

panelOne.add(buttonOne);
panelOne.setBackground(Color.BLUE);

panelCont.add(panelOne, "1");
panelCont.add(panelTwo, "2");
cards.show(panelCont, "1");

buttonOne.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cards.show(panelCont, "2");
}
});

frame.add(panelCont);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new lay();
}
});
}

}

class PanelTwo extends JPanel {

JButton buttonTwo;
CardLayout layout;
JPanel panelCont;

public PanelTwo(final CardLayout layout, final JPanel panelCont) {
this.layout = layout;
this.panelCont = panelCont;
buttonTwo = new JButton("Go to one");

add(buttonTwo);
setBackground(Color.GREEN);

buttonTwo.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
layout.show(panelCont, "1");
}
});

}
}

I also initialized the CardLayout in the lay constructor before initializing the PanelTwo. This avoids a NullPointerException

Call variable from other java class

One problem I see is that your LoginScreen class is a JFrame, and a JFrame's behavior is to not stop program flow from the calling code when it is displayed, so even if you could extract the login name and password from this object in your later code, you'll be extracting it too early, before the user has had a time to enter anything.

Suggestions:

  • Most important is that you're trying to run code that won't compile. Never do this as this is guaranteed to always fail. Instead, fix compilation issues before trying to run your program.
  • Your LoginScreen should be a modal JDialog and not a JFrame.
  • You first display this window in order to get the user's input.
  • Key point here is, that because it is a modal JDialog, the calling code flow stops when the dialog is displayed.
  • The calling code then resumes once the dialog has been dealt with and is no longer visible, meaning once the user has either entered data or canceled the dialog.
  • At that time, you then get the login user's name and password (best if the latter is obtained as a char[]) from the LoginScreen instance by calling getter methods, and checking to be sure that they are not null. i.e., LoginScreen should have a public String getUserName() method and a public char[] getPassword() method.
  • The calling code can now use this information in the database.
  • And yeah, please learn Java naming conventions, and please comply with them by having your class names start with upper-case letters and method and variable names with lower-case letters. This will make it easier for folks trying to understand your code and help you, namely the volunteers here, do it better.

Edit

Note also that a JOptionPane is really nothing more than a modal JDialog, and this can be used for your purposes as well, and easily too. For example, in the example code below I create an InputForm JPanel and then place that JPanel into the JOptionPane:

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.*;

@SuppressWarnings("serial")
public class MainFoo extends JPanel {
private static final int COLUMNS = 10;
private JTextField userNameField = new JTextField(COLUMNS);
private JTextField passwordField = new JTextField(COLUMNS);
private InputForm inputForm = new InputForm();

public MainFoo() {
add(new JLabel("User Name:"));
add(userNameField);
add(Box.createHorizontalStrut(15));
add(new JLabel("Password:"));
add(passwordField);
add(new JButton(new LogInAction("Log in", KeyEvent.VK_L)));
}

private class LogInAction extends AbstractAction {
public LogInAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}

@Override
public void actionPerformed(ActionEvent e) {
int result = JOptionPane.showConfirmDialog(null, inputForm, "Input Form",
JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
if (result == JOptionPane.OK_OPTION) {
userNameField.setText(inputForm.getUserName());

// ***** never do this! *****
// Never change a password into a String.
// This is for demo purposes only.
passwordField.setText(new String(inputForm.getPassword()));
}
}
}

private static void createAndShowGui() {
JFrame frame = new JFrame("MainFoo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MainFoo());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

@SuppressWarnings("serial")
class InputForm extends JPanel {
private static final int COLUMNS = 10;
private static final int GAP = 3;
private static final Insets LABEL_INSETS = new Insets(GAP, GAP, GAP, 15);
private static final Insets TEXTFIELD_INSETS = new Insets(GAP, GAP, GAP, GAP);
private JTextField userNameField = new JTextField(COLUMNS);
private JPasswordField passwordField = new JPasswordField(COLUMNS);

public InputForm() {
setLayout(new GridBagLayout());
addLabel("User Name:", 0);
addTextField(userNameField, 0);

addLabel("Password:", 1);
addTextField(passwordField, 1);

}

public String getUserName() {
return userNameField.getText();
}

public char[] getPassword() {
return passwordField.getPassword();
}

private void addTextField(JTextField field, int row) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = 1;
gbc.gridheight = 1;
gbc.gridx = 1;
gbc.gridy = row;
gbc.anchor = GridBagConstraints.EAST;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = TEXTFIELD_INSETS;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
add(field, gbc);
}

private void addLabel(String text, int row) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = 1;
gbc.gridheight = 1;
gbc.gridx = 0;
gbc.gridy = row;
gbc.anchor = GridBagConstraints.WEST;
gbc.fill = GridBagConstraints.BOTH;
gbc.insets = LABEL_INSETS;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
add(new JLabel(text), gbc);
}
}


Related Topics



Leave a reply



Submit