Jpanel & Components Change Position Automatically

JPanel & components change position automatically

I think the original (non-broken) layout looks quirky and would make it difficult for the end user to follow the rows and labels/fields. I suggest instead using a GroupLayout to right align the labels, and left align the fields that contain the values. Like this:

Sample Image

import java.awt.*;
import java.util.HashMap;
import java.util.Map;
import javax.swing.*;

class TwoColumnLayoutWithHeader {

/**
* Provides a JPanel with two columns (labels & fields) laid out using
* GroupLayout. The arrays must be of equal size.
*
* Typical fields would be single line textual/input components such as
* JTextField, JPasswordField, JFormattedTextField, JSpinner, JComboBox,
* JCheckBox.. & the multi-line components wrapped in a JScrollPane -
* JTextArea or (at a stretch) JList or JTable.
*
* @param labels The first column contains labels.
* @param fields The last column contains fields.
* @param addMnemonics Add mnemonic by next available letter in label text.
* @return JComponent A JPanel with two columns of the components provided.
*/
public static JComponent getTwoColumnLayout(
JLabel[] labels,
JComponent[] fields,
boolean addMnemonics) {
if (labels.length != fields.length) {
String s = labels.length + " labels supplied for "
+ fields.length + " fields!";
throw new IllegalArgumentException(s);
}
JComponent panel = new JPanel();
GroupLayout layout = new GroupLayout(panel);
panel.setLayout(layout);
// Turn on automatically adding gaps between components
layout.setAutoCreateGaps(true);
// Create a sequential group for the horizontal axis.
GroupLayout.SequentialGroup hGroup = layout.createSequentialGroup();
GroupLayout.Group yLabelGroup = layout.createParallelGroup(GroupLayout.Alignment.TRAILING);
hGroup.addGroup(yLabelGroup);
GroupLayout.Group yFieldGroup = layout.createParallelGroup();
hGroup.addGroup(yFieldGroup);
layout.setHorizontalGroup(hGroup);
// Create a sequential group for the vertical axis.
GroupLayout.SequentialGroup vGroup = layout.createSequentialGroup();
layout.setVerticalGroup(vGroup);

int p = GroupLayout.PREFERRED_SIZE;
// add the components to the groups
for (JLabel label : labels) {
yLabelGroup.addComponent(label);
}
for (Component field : fields) {
yFieldGroup.addComponent(field, p, p, p);
}
for (int ii = 0; ii < labels.length; ii++) {
vGroup.addGroup(layout.createParallelGroup().
addComponent(labels[ii]).
addComponent(fields[ii], p, p, p));
}

if (addMnemonics) {
addMnemonics(labels, fields);
}

return panel;
}

private final static void addMnemonics(
JLabel[] labels,
JComponent[] fields) {
Map<Character, Object> m = new HashMap<Character, Object>();
for (int ii = 0; ii < labels.length; ii++) {
labels[ii].setLabelFor(fields[ii]);
String lwr = labels[ii].getText().toLowerCase();
for (int jj = 0; jj < lwr.length(); jj++) {
char ch = lwr.charAt(jj);
if (m.get(ch) == null && Character.isLetterOrDigit(ch)) {
m.put(ch, ch);
labels[ii].setDisplayedMnemonic(ch);
break;
}
}
}
}

/**
* Provides a JPanel with two columns (labels & fields) laid out using
* GroupLayout. The arrays must be of equal size.
*
* @param labelStrings Strings that will be used for labels.
* @param fields The corresponding fields.
* @return JComponent A JPanel with two columns of the components provided.
*/
public static JComponent getTwoColumnLayout(
String[] labelStrings,
JComponent[] fields) {
JLabel[] labels = new JLabel[labelStrings.length];
for (int ii = 0; ii < labels.length; ii++) {
labels[ii] = new JLabel(labelStrings[ii]);
}
return getTwoColumnLayout(labels, fields);
}

/**
* Provides a JPanel with two columns (labels & fields) laid out using
* GroupLayout. The arrays must be of equal size.
*
* @param labels The first column contains labels.
* @param fields The last column contains fields.
* @return JComponent A JPanel with two columns of the components provided.
*/
public static JComponent getTwoColumnLayout(
JLabel[] labels,
JComponent[] fields) {
return getTwoColumnLayout(labels, fields, true);
}

public static String getProperty(String name) {
return name + ": \t"
+ System.getProperty(name)
+ System.getProperty("line.separator");
}

public static void main(String[] args) {
Runnable r = new Runnable() {

@Override
public void run() {
JComponent[] components = {
new JTextField(15),
new JTextField(10),
new JTextField(8),
new JSpinner(new SpinnerNumberModel(1,0,10,1)),
new JSpinner(new SpinnerNumberModel(9.95,0d,100d,.01)),
new JSpinner(new SpinnerNumberModel(9.95,0d,1000d,.01)),
new JSpinner(new SpinnerNumberModel(9.95,0d,100d,.01)),
new JSpinner(new SpinnerNumberModel(9.95,0d,1000d,.01)),
new JSpinner(new SpinnerNumberModel(9.95,0d,100d,.01)),
new JSpinner(new SpinnerNumberModel(9.95,0d,1000d,.01))
};

String[] labels = {
"Product Name:",
"Product Unit Name:",
"Purchase Date:",
"Quantity:",
"Price Per Unit:",
"Total Price:",
"Discount:",
"Total:",
"VAT:",
"Grand Total:"
};

JComponent labelsAndFields = getTwoColumnLayout(labels,components);
JComponent orderForm = new JPanel(new BorderLayout(5,5));
orderForm.add(new JLabel("Purchase Form", SwingConstants.CENTER),
BorderLayout.PAGE_START);
orderForm.add(labelsAndFields, BorderLayout.CENTER);

JOptionPane.showMessageDialog(null, orderForm);
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
SwingUtilities.invokeLater(r);
}
}

Java Swing: Components automatically change position when a certain component updates

The components are added to the same panel so each is centered based on the maximum width of all three components. As the width of the top label changes the others are also adjusted.

The solution is to separate the top label from the other two labels.

One way would be:

    //panel.add(label1);
panel.add(label2);
panel.add(label3);

//label1.setAlignmentX(Component.CENTER_ALIGNMENT);
label1.setHorizontalAlignment(JLabel.CENTER); // added
label2.setAlignmentX(Component.CENTER_ALIGNMENT);
label3.setAlignmentX(Component.CENTER_ALIGNMENT);

frame.add(label1, BorderLayout.PAGE_START); // added
frame.getContentPane().add(panel);

JPanel changes shape/position within JFrame when JButton is pressed. Why?

The reason your UI changes is because the look that you think is correct (the initial look) is actually wrong, and the resized version is the "correct" version.

Typically, you'd call pack() after adding components to a container, which tries to display the contents of that container at their preferred sizes. To see the correct UI before and after the button press, following your call to repaint(), add:

window.pack();

You may think that looks terrible (which it does) but it's exactly what your code is asking for, and is therefore the "correct" version.

Take note that you are trying to set sizes with explicit calls to setSize(), which is a bad practice in Swing. At most, you should be setting preferred sizes and letting the layout manager handle the details. When you try to micromanage component sizes and locations, you can often make it look good on one platform, but irredeemably bad on others. Remember that Java is supposed to be the "write once, run anywhere" language.

When you want more control over your layout, you should explicitly specify and use a layout manager, rather than just accepting the default layout. In almost every non-trivial UI, GridBagLayout is your best bet.

Finally, you don't need to explicitly call repaint() on your UI when something changes. Typically, you'd call paint() and repaint() when you are working with graphics. Let Swing handle the painting automatically.

How to set position to JComponent in BoxLayout?

If your goal is to have the button above the image, and have the button's width expand with the image, then:

  • Get rid of your use of null layouts and .setBounds(...) (this is just good general advice)
  • Put the JLabel with the image into a JPanel that uses BorderLayout with the JLabel in the BorderLayout.CENTER position
  • Put the button above the JLabel in the same JPanel using the BorderLayout.PAGE_START position.
  • Then put that JPanel wherever it is needed in the GUI, nesting JPanels, each using their own layout manager.

The BorderLayout will allow the center component to fill that position, and will expand the PAGE_START and PAGE_END positions to fill the width necessary. If the top and bottom components are wider, then this will also expand the width of the container.

How to position JPanel to upper right corner of JFrame

You can use a BorderLayout contentPane, as the frame's content pane. This pane would include:

  1. In its BorderLayout.NORTH position, a JPanel (timerPane) with a FlowLayout (with orientation ComponentOrientation.RIGHT_TO_LEFT). You can use this panel to house your timer Component.
  2. In its BorderLayout.CENTER position, your board.

Your code (modified to include this considerations) would look like this:

private final JFrame frame = new JFrame("myBoardGame");
private JPanel contentPane = new JPanel(new BorderLayout());
private JPanel timerPane = new JPanel(new FlowLayout());

public ShowBoard(Board board){
timerPane.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
contentPane.add(timerPane, BorderLayout.NORTH);
contentPane.add(board, BorderLayout.CENTER);

frame.setResizable(false);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setContentPane(contentPane);
frame.pack();
frame.setVisible(true);

this.board = board;
getKeyBindings();
}

Swing: Dynamically change visibility of components

when u set the visibility of components like JPanels. JVM automatically call revalidate() and repaint() method when u set the visibility to true. u does not need to call the all these method. and it will work for all layout

why cant i change the position of the panel inside a frame?

  1. Set your main panel's layout to BorderLayout.
  2. Create a panel just for your buttons and add this panel to your main panel's NORTH position.

Here is a working example:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

import javax.swing.AbstractButton;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class ssGUI extends JPanel implements ActionListener {
private static final long serialVersionUID = 1L;
protected JButton b1, bConnect, bDisconnect, b2;
protected JPanel canvas;

public ssGUI() {
setLayout(new BorderLayout());
// run button
b1 = new JButton("do something");
b1.setVerticalTextPosition(AbstractButton.CENTER);
b1.setHorizontalTextPosition(AbstractButton.LEADING);
b1.setMnemonic(KeyEvent.VK_D);
b1.addActionListener(this);
b1.setEnabled(false);
// connect button
bConnect = new JButton("Connect");
bConnect.setMnemonic(KeyEvent.VK_E);
bConnect.addActionListener(this);
bConnect.setEnabled(true);
// disconnect button
bDisconnect = new JButton("Disconnect");
bDisconnect.setMnemonic(KeyEvent.VK_E);
bDisconnect.addActionListener(this);
bDisconnect.setEnabled(false);
// clean nmea data button
b2 = new JButton("do something else");
b2.setMnemonic(KeyEvent.VK_E);
b2.addActionListener(this);
b2.setEnabled(false);
// drawing panel
canvas = new JPanel();
canvas.setBackground(Color.white);

JPanel topPanel = new JPanel();
topPanel.add(b1);
topPanel.add(bConnect);
topPanel.add(bDisconnect);
topPanel.add(b2);
add(topPanel, BorderLayout.NORTH);

add(canvas, BorderLayout.CENTER);
}

public static void createAndShowGUI() {
JFrame frame = new JFrame("Range Adjustment GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ssGUI newContentPane = new ssGUI();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
frame.setLocation(500, 500);
frame.setSize(500, 500);
}

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

@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub

}
}


Related Topics



Leave a reply



Submit