Nicer way to layout TextFields aligned to the top of JPanel - java

If I use GridLayout or BoxLayout for bunch of JTextField and JLabel pairs it will equally split are of JPanel among the text-fields.
it looks like this:
What I want looks like this ( with text-fields squeezed to the top ):
and I was able to achive that following this answer. The code is:
public void forceSize( int szx, int szy, JComponent comp ){
comp.setPreferredSize( new Dimension( szx, szy ) );
comp.setMaximumSize ( new Dimension( szx, szy ) );
comp.setMinimumSize ( new Dimension( szx, szy ) );
};
public void addLabeledBox( String label_str, JTextField valField, JPanel labelPane, JPanel valuePane ){
JLabel label = new JLabel( label_str );
label.setLabelFor( valField );
labelPane.add( label );
forceSize( 100, 20, label );
forceSize( 100, 20, valField );
valuePane.add( valField );
}
public JComponent makeCityPanel( ){
//JPanel labelPane = new JPanel( new GridLayout(0,1) );
//JPanel valuePane = new JPanel( new GridLayout(0,1) );
JPanel labelPane = new JPanel( ); labelPane.setLayout( new BoxLayout( labelPane, BoxLayout.Y_AXIS ) );
JPanel valuePane = new JPanel( ); valuePane.setLayout( new BoxLayout( valuePane, BoxLayout.Y_AXIS ) );
//panel.setLayout(new GridBagLayout());
//panel.setLayout(new GridBagLayout());
name_field = new JTextField( );
addLabeledBox( "name", name_field, labelPane, valuePane );
ix_field = new JFormattedTextField( NumberFormat.getNumberInstance() );
addLabeledBox( "ix", ix_field, labelPane, valuePane);
iy_field = new JFormattedTextField( NumberFormat.getNumberInstance() );
addLabeledBox( "iy", iy_field, labelPane, valuePane);
factorySpace_field = new JFormattedTextField( NumberFormat.getNumberInstance() );
addLabeledBox( "FactorySpace", factorySpace_field, labelPane, valuePane);
storeSpace_field = new JFormattedTextField( NumberFormat.getNumberInstance() );
addLabeledBox( "StoreSapce", storeSpace_field, labelPane, valuePane );
//JScrollPane cityPanel = new JScrollPane( );
JPanel cityPanel = new JPanel(new GridLayout(1,0));
cityPanel.add( labelPane );
cityPanel.add( valuePane );
cityPanel.setSize( 100 , 100 );
return cityPanel;
}
However, I have feeling that this is not the correct way. ( Also here they say that it is bad ).
So is there a better way?

Another way is to nest panels with different layout managers:
Make the layout of your "main" panel a BorderLayout and add this panel to the tabbed pane.
Create a second "child" panel using your GridLayout and add your components to the panel.
Add the "child" panel to the BorderLayout.PAGE_Start of the "main" panel. This will respect the preferred height of the panel.
Or you can always use a GridBagLayout. It is more involved because you need to specify constraints for each component, but you can get your desired effect with a single panel. Read the section from the Swing tutorial on How to Use GridBagLayout for more information and working examples.

A great layout to use is MigLayout.
Here is a bit of code which achieves what you want using the layout.
import javax.swing.*;
import java.awt.*;
import net.miginfocom.swing.MigLayout;
public class SimpleGUI
{
public JFrame myMainWindow = new JFrame("City View");
JPanel guiPanel = new JPanel();
JLabel name = new JLabel("Name");
JLabel ix = new JLabel("ix");
JLabel iy = new JLabel("iy");
JLabel factorySpace = new JLabel("Factory Space");
JLabel storeSpace = new JLabel("Store Space");
JTextField t1 = new JTextField();
JTextField t2 = new JTextField();
JTextField t3 = new JTextField();
JTextField t4 = new JTextField();
JTextField t5 = new JTextField();
int fontMetrics;
FontMetrics fM;
public void runGUI()
{
myMainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myMainWindow.setLayout(new GridLayout(1,1));
createTestPanel();
myMainWindow.getContentPane().add(guiPanel);
myMainWindow.setVisible(true);
myMainWindow.pack();
myMainWindow.setMinimumSize(new Dimension(myMainWindow.getBounds().getSize()));
}
public void createTestPanel()
{
MigLayout layout = new MigLayout("wrap 2", "[grow]");
guiPanel.setLayout(layout);
fM = name.getFontMetrics(name.getFont());
fontMetrics = fM.stringWidth("Name");
name.setSize(fontMetrics+10,25);
guiPanel.add(name);
guiPanel.add(t1,"growx, width 100:100:");
fM = ix.getFontMetrics(ix.getFont());
fontMetrics = fM.stringWidth("ix");
ix.setSize(fontMetrics+10,25);
guiPanel.add(ix);
guiPanel.add(t2,"growx, width 100:100:");
fM = iy.getFontMetrics(iy.getFont());
fontMetrics = fM.stringWidth("iy");
iy.setSize(fontMetrics+10,25);
guiPanel.add(iy);
guiPanel.add(t3,"growx, width 100:100:");
fM = factorySpace.getFontMetrics(factorySpace.getFont());
fontMetrics = fM.stringWidth("Factory Space");
factorySpace.setSize(fontMetrics+10,25);
guiPanel.add(factorySpace);
guiPanel.add(t4,"growx, width 100:100:");
fM = storeSpace.getFontMetrics(storeSpace.getFont());
fontMetrics = fM.stringWidth("Store Space");
storeSpace.setSize(fontMetrics+10,25);
guiPanel.add(storeSpace);
guiPanel.add(t5,"growx, width 100:100:");
}
public static void main(String[] args)
{
SimpleGUI sG = new SimpleGUI();
sG.runGUI();
}
}
However when you resize this it might look better if when adding the labels you use something like this.
JLabel someLabel = new JLabel("something");
...
MigLayout layout = new MigLayout("wrap 2", "[right][grow]");
guiPanel.setLayout(layout);
guiPanel.add(someLabel,"grow");
Which will give a GUI which looks like this.
Some example code for this would be
import javax.swing.*;
import java.awt.*;
import net.miginfocom.swing.MigLayout;
public class SimpleGUI
{
public JFrame myMainWindow = new JFrame("City View");
JPanel guiPanel = new JPanel();
JLabel name = new JLabel("Name");
JLabel ix = new JLabel("ix");
JLabel iy = new JLabel("iy");
JLabel factorySpace = new JLabel("Factory Space");
JLabel storeSpace = new JLabel("Store Space");
JTextField t1 = new JTextField();
JTextField t2 = new JTextField();
JTextField t3 = new JTextField();
JTextField t4 = new JTextField();
JTextField t5 = new JTextField();
public void runGUI()
{
myMainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myMainWindow.setLayout(new GridLayout(1,1));
createTestPanel();
myMainWindow.getContentPane().add(guiPanel);
myMainWindow.setVisible(true);
myMainWindow.pack();
myMainWindow.setMinimumSize(new Dimension(myMainWindow.getBounds().getSize()));
}
public void createTestPanel()
{
MigLayout layout = new MigLayout("wrap 2", "[right][grow]");
guiPanel.setLayout(layout);
guiPanel.add(name);
guiPanel.add(t1,"growx, width 100:100:");
guiPanel.add(ix);
guiPanel.add(t2,"growx, width 100:100:");
guiPanel.add(iy);
guiPanel.add(t3,"growx, width 100:100:");
guiPanel.add(factorySpace);
guiPanel.add(t4,"growx, width 100:100:");
guiPanel.add(storeSpace);
guiPanel.add(t5,"growx, width 100:100:");
}
public static void main(String[] args)
{
SimpleGUI sG = new SimpleGUI();
sG.runGUI();
}
}

This looks to me like a classic case for GroupLayout. Unfortunately, the tutorial for GroupLayout is rather overly fond of 'chaining' method calls together, but if you go through it once you should be able to do yours, which is a fairly simple case.
The basic idea is that you add each component once to a vertical layout and once to a horizontal layout; think of it as creating rows columns and rows. Once nice thing about this as compared to GridLayout is that the layout and field 'columns' don't need to be the same width.

Related

How to set layout in java GUI swing?

I am trying to create a register form for my application(school project), I wanted to set the layout to BoxLayout but the Jtextfields and combo box is having issue as you can see below, does this issue relates to setSize() or is it something I am doing incorrect,I just want the Jtextfields sorts vertically , I appreciate the support
private JPanel SetUpRegister() {
JLabel registerLabel = new JLabel("Registera");
registerLabel.setFont(new Font("Arial", Font.BOLD, 30));
loginRegisterInput = new JTextField(INPUT_FIELD_WIDTH);
passwordRegisterInput = new JTextField(INPUT_FIELD_WIDTH);
fnRegisterInput = new JTextField(INPUT_FIELD_WIDTH);
lnRegisterInput = new JTextField(INPUT_FIELD_WIDTH);
ageRegisterInput = new JTextField(INPUT_FIELD_WIDTH);
String[] genderlist = new String[] { "Male", "Female", "Other" };
JComboBox<String> registerList = new JComboBox<>(genderlist);
JPanel registerPanel = new JPanel();
registerPanel.setBackground(new Color(255, 140, 0));
registerPanel.add(registerLabel);
registerPanel.add(loginRegisterInput);
registerPanel.add(passwordRegisterInput);
registerPanel.add(fnRegisterInput);
registerPanel.add(lnRegisterInput);
registerPanel.add(ageRegisterInput);
registerPanel.add(registerList);
registerPanel.setLayout(new BoxLayout(registerPanel,BoxLayout.Y_AXIS));
return registerPanel;
}
The input fields are huge
The BoxLayout will attempt to resize components when extra space is available on the panel. It will resize a component up to its maximum size.
For some reason the maximum height of a JTextField is Integer.MAX_VALUE which makes no sense to me, since the height of the text never changes as you enter more text.
In any case you have a couple of choices:
Use a different layout manager, like the GridBagLayout. The GridBagLayout, will respect the preferred size of the text fields.
Create a custom JTestField and override the getMaximumSize() method to return the preferred height of the component
Use a wrapper panel.
For the wrapper panel you could do:
JPanel wrapper = new JPanel( new BorderLayout() );
wrapper.add(registerPanel, BorderLayout.PAGE_START);
return wrapper;
//return registerPanel;
The BorderLayout will respect the preferred height of any component added to the PAGE_START, so there is no need for the BoxLayout to resize any component.
private JPanel SetUpRegister() {
JLabel registerLabel = new JLabel("Registera");
JLabel registerLabel1 = new JLabel("Login :");
JLabel registerLabel2 = new JLabel("Password :");
JLabel registerLabel3 = new JLabel("First Name :");
JLabel registerLabel4 = new JLabel("Last Name :");
JLabel registerLabel5 = new JLabel("Age :");
JLabel registerLabel6 = new JLabel("Gender :");
JLabel registerLabel7 = new JLabel("Bio :");
registerLabel.setFont(new Font("Arial", Font.BOLD, 30));
JButton createAccButton = new JButton("Create");
createAccButton.addActionListener(new CreateAccountListener());
loginRegisterInput = new JTextField(INPUT_FIELD_WIDTH);
passwordRegisterInput = new JTextField(INPUT_FIELD_WIDTH);
fnRegisterInput = new JTextField(INPUT_FIELD_WIDTH);
lnRegisterInput = new JTextField(INPUT_FIELD_WIDTH);
ageRegisterInput = new JTextField(INPUT_FIELD_WIDTH);
bioRegisterInput = new JTextField(INPUT_FIELD_WIDTH);
String[] genderlist = new String[] { "Male", "Female", "Other" };
registerList = new JComboBox(genderlist);
JPanel registerPanel = new JPanel();
registerPanel.setLayout(new BoxLayout(registerPanel, BoxLayout.Y_AXIS));
registerPanel.add(registerLabel);
JPanel registerLabPanel = new JPanel();
registerLabPanel.setLayout(new FlowLayout());
registerLabPanel.add(registerLabel);
JPanel usernamePanel = new JPanel();
usernamePanel.setLayout(new FlowLayout());
usernamePanel.add(registerLabel1);
usernamePanel.add(loginRegisterInput);
JPanel passwordPanel = new JPanel();
passwordPanel.setLayout(new FlowLayout());
passwordPanel.add(registerLabel2);
passwordPanel.add(passwordRegisterInput);
JPanel fnPanel = new JPanel();
fnPanel.setLayout(new FlowLayout());
fnPanel.add(registerLabel3);
fnPanel.add(fnRegisterInput);
JPanel lnPanel = new JPanel();
lnPanel.setLayout(new FlowLayout());
lnPanel.add(registerLabel4);
lnPanel.add(lnRegisterInput);
JPanel agePanel = new JPanel();
agePanel.setLayout(new FlowLayout());
agePanel.add(registerLabel5);
agePanel.add(ageRegisterInput);
JPanel genderPanel = new JPanel();
genderPanel.setLayout(new FlowLayout());
genderPanel.add(registerLabel6);
genderPanel.add(registerList);
JPanel bioPanel = new JPanel();
bioPanel.setLayout(new FlowLayout());
bioPanel.add(registerLabel7);
bioPanel.add(bioRegisterInput);
JPanel buttonLoginPanel = new JPanel();
buttonLoginPanel.setLayout(new FlowLayout());
buttonLoginPanel.add(createAccButton);
registerPanel.add(registerLabel);
registerPanel.add(usernamePanel);
registerPanel.add(passwordPanel);
registerPanel.add(fnPanel);
registerPanel.add(lnPanel);
registerPanel.add(agePanel);
registerPanel.add(genderPanel);
registerPanel.add(bioPanel);
registerPanel.add(buttonLoginPanel);
return registerPanel;
}
I fixed the issue by making a Panel for each input and label

Is there an easier way to shift 'older' components down when adding newer components (whenever a button is pressed)?

I've tried looking for an answer to my question, but couldn't find anything similar. If it's already been asked, please link. Thanks in advance.
The layout of the main panel, mainPanel, is GridBagLayout. It has three buttons. Two of them are duds (for the purpose of this question). The middle button, butt2, creates a JPanel with other components in it every time butt2 is pressed.
Because butt2 is in the middle, and butt3 is directly below it, I have an int variable, tracker2, that tracks the gridy of butt2. Every time butt2 is pressed, I create a new JPanel that goes under butt2, increment tracker2, and then remove butt3 and add it below the newer component.
import java.util.List;
import java.util.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class Demo implements ActionListener
public static void main(String[] args) {
Demo demo = new Demo();
}
private JFrame frame;
private JPanel mainPanel;
private JButton butt1, butt2, butt3;
private GridBagConstraints gb;
private List<JTextField> list;
private int count, tracker2;
public Demo() {
frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(true);
frame.setBounds(0, 0, 800, 800);
list = new ArrayList<JTextField>();
count = 0;
tracker2 = 0;
commence();
}
private void commence() {
gb = new GridBagConstraints();
gb.anchor = GridBagConstraints.FIRST_LINE_START;
gb.weightx = 1;
gb.insets = new Insets(50, 5, 0, 20);
mainPanel = new JPanel();
mainPanel.setBackground(Color.white);
mainPanel.setLayout( new GridBagLayout() );
butt1 = new JButton("One");
butt1.setPreferredSize( new Dimension(100, 50) );
// Add to panel
gb.gridx = 0;
gb.gridy = 0;
mainPanel.add( butt1, gb);
butt2 = new JButton("Two");
butt2.setPreferredSize( new Dimension(100, 50) );
butt2.addActionListener(this);
// Add to panel
gb.gridy++;
tracker2 = gb.gridy;
mainPanel.add( butt2, gb );
butt3 = new JButton("Three");
butt3.setPreferredSize( new Dimension(100, 50) );
// Add to panel
gb.gridy++;
mainPanel.add( butt3, gb );
frame.add(mainPanel);
frame.setVisible(true);
frame.repaint();
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource().equals( butt2 )) {
commence2();
}
}
private void commence2() {
gb.insets = new Insets( 0, 0, 0, 0 );
list.add( new JTextField(30) );
JLabel label = new JLabel("LABEL 2 ");
label.setDisplayedMnemonic( KeyEvent.VK_N );
label.setLabelFor( list.get(count) );
JPanel panel = new JPanel( new FlowLayout(FlowLayout.LEFT, 10, 3));
panel.setBackground( Color.white );
panel.add(label);
panel.add(list.get( count ));
// Add to mainPanel
tracker2++;
gb.gridy = tracker2;
mainPanel.add( panel, gb );
updateFrame();
// Increment count
count++;
frame.revalidate();
frame.repaint();
}
private void updateFrame() {
mainPanel.remove( butt3 );
gb.insets = new Insets(50, 5, 0, 20);
gb.gridy = tracker2 + 1;
mainPanel.add( butt3, gb );
}
}
Is there an easier way to do this or a Layout that automatically does this for me?
Yes, there is an easier way. Instead of adding the new text fields to your mainPanel use an additional Container. E.g.
public class Demo2 implements ActionListener {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Demo2();
}
});
}
private JFrame frame;
private JPanel textPanel;
private JButton butt1, butt2, butt3;
public Demo2() {
frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(true);
frame.setBounds(0, 0, 800, 800);
commence();
}
private void commence() {
GridBagConstraints gb = new GridBagConstraints();
gb.anchor = GridBagConstraints.FIRST_LINE_START;
gb.weightx = 1;
gb.insets = new Insets(50, 5, 0, 20);
JPanel mainPanel = new JPanel();
mainPanel.setBackground(Color.white);
mainPanel.setLayout( new GridBagLayout() );
butt1 = new JButton("One");
butt1.setPreferredSize( new Dimension(100, 50) );
// Add to panel
gb.gridx = 0;
gb.gridy = 0;
mainPanel.add( butt1, gb);
butt2 = new JButton("Two");
butt2.setPreferredSize( new Dimension(100, 50) );
butt2.addActionListener(this);
// Add to panel
gb.gridy++;
gb.insets = new Insets(50, 5, 0, 0);
mainPanel.add( butt2, gb );
textPanel = new JPanel(new GridLayout(0, 1));
// Add to panel
gb.gridy++;
gb.insets = new Insets(0, 5, 0, 20);
mainPanel.add( textPanel, gb );
butt3 = new JButton("Three");
butt3.setPreferredSize( new Dimension(100, 50) );
// Add to panel
gb.gridy++;
gb.insets = new Insets(50, 5, 0, 20);
mainPanel.add( butt3, gb );
frame.add(mainPanel);
frame.setVisible(true);
frame.repaint();
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource().equals( butt2 )) {
commence2();
}
}
private void commence2() {
JTextField jtf = new JTextField(30);
JLabel label = new JLabel("LABEL 2 ");
label.setDisplayedMnemonic(KeyEvent.VK_N );
label.setLabelFor( jtf );
JPanel panel = new JPanel( new FlowLayout(FlowLayout.LEFT, 10, 3));
panel.setBackground( Color.white );
panel.add(label);
panel.add( jtf );
// Add to mainPanel
textPanel.add( panel );
textPanel.revalidate();
frame.revalidate();
frame.repaint();
}
}
In the above code, textPanel serves as container for the new text fields.

Java Layout with Component always in Top Right

The primary GUI of my application is composed of a JDesktopPane at the CENTER of a frame's content pane using a BorderLayout. I am hoping to have a component placed in the top right of the screen that still allows the user to drag JInternalFrames within the space to the left and and bottom of this component.
Setting the component to the NORTH or EAST of the BorderLayout seems to fill the entire space. I am thinking BorderLayout may not be the best layout manager for what I am trying to accomplish? Any suggestions on a better approach?
Check out the OverlayLayout. It allows you to stack components on top of one another.
You need to manipulate the setAlignmentX(..) and setAlignmentY(...)` methods to get the layout you want. It is not always intuitive how these alignments work together but setting the component to the top/left is relatively easy.
Here is a little demo for you to play with:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class OverlayLayoutTest extends JPanel
implements ActionListener
{
JPanel green;
JPanel red;
JLabel greenLabel;
JLabel redLabel;
JComboBox greenAlignmentX;
JComboBox greenAlignmentY;
JComboBox redAlignmentX;
JComboBox redAlignmentY;
public OverlayLayoutTest()
{
setLayout( new BorderLayout(10, 10) );
add(createNorthPanel(), BorderLayout.NORTH);
add(createCenterPanel(), BorderLayout.CENTER);
add(createSouthPanel(), BorderLayout.SOUTH);
}
private JPanel createNorthPanel()
{
JPanel panel = new JPanel();
panel.add( new JLabel("Green:") );
greenLabel = new JLabel();
panel.add( greenLabel );
panel.add( new JLabel("Red:") );
redLabel = new JLabel();
panel.add( redLabel );
return panel;
}
private JPanel createCenterPanel()
{
JPanel panel = new JPanel();
panel.setLayout( new OverlayLayout(panel) );
panel.setBackground( Color.ORANGE );
panel.setPreferredSize( new Dimension(200, 200) );
red = new JPanel();
red.setBackground( Color.RED );
red.setPreferredSize( new Dimension(50, 50) );
red.setMaximumSize( red.getPreferredSize() );
red.setMinimumSize( red.getPreferredSize() );
panel.add( red );
green = new JPanel();
green.setBackground( Color.GREEN );
green.setPreferredSize( new Dimension(100, 100) );
green.setMaximumSize( green.getPreferredSize() );
green.setMinimumSize( green.getPreferredSize() );
panel.add( green );
JPanel wrap = new JPanel();
wrap.add( panel );
return wrap;
}
private JPanel createSouthPanel()
{
JPanel panel = new JPanel( new GridLayout(1, 0, 10, 10) );
JPanel green = new JPanel(new GridLayout(0, 2, 5, 5) );
green.setBorder( new TitledBorder("Green Alignment") );
green.add( new JLabel("X Alignment:") );
greenAlignmentX = createComboBox();
green.add( greenAlignmentX );
green.add( new JLabel("Y Alignment:") );
greenAlignmentY = createComboBox();
green.add( greenAlignmentY );
panel.add( green );
JPanel red = new JPanel(new GridLayout(0, 2, 5, 5) );
red.setBorder( new TitledBorder("Red Alignment") );
red.add( new JLabel("X Alignment:") );
redAlignmentX = createComboBox();
red.add( redAlignmentX );
red.add( new JLabel("Y Alignment:") );
redAlignmentY = createComboBox();
red.add( redAlignmentY );
panel.add( red );
JButton reset = new JButton("Reset Alignment");
reset.addActionListener( this );
panel.add( reset );
return panel;
}
public void actionPerformed(ActionEvent e)
{
green.setAlignmentX( ((Float)greenAlignmentX.getSelectedItem()) );
green.setAlignmentY( ((Float)greenAlignmentY.getSelectedItem()) );
red.setAlignmentX( ((Float)redAlignmentX.getSelectedItem()) );
red.setAlignmentY( ((Float)redAlignmentY.getSelectedItem()) );
JPanel parent = (JPanel)green.getParent();
parent.revalidate();
/*
System.out.print(green.getAlignmentX() + " : ");
System.out.print(green.getAlignmentY() + " : ");
System.out.print(red.getAlignmentX() + " : ");
System.out.print(red.getAlignmentY() + " : ");
System.out.println();
*/
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
greenLabel.setText( green.getLocation().toString() );
redLabel.setText( red.getLocation().toString() );
}
});
}
private JComboBox createComboBox()
{
JComboBox<Float> comboBox = new JComboBox<Float>();
comboBox.addItem( new Float(0f) );
comboBox.addItem( new Float(0.25f) );
comboBox.addItem( new Float(0.5f) );
comboBox.addItem( new Float(0.75f) );
comboBox.addItem( new Float(1.0f) );
comboBox.setSelectedItem(0.5f);
return comboBox;
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("OverlayLayoutTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new OverlayLayoutTest() );
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
set the alignment X values to 1.0 for both components
set the alignment Y values to 0.0 for both components
and you should get the layout you want.
Edit:
Missed the part about dragging a JInternalFrame. So this imples you are using a JDesktopPane to support the dragging. A JDesktopPane uses a null layout to allow you to drag components around.
There is no reason you can't add another component (other than a JInternalFrame) to the desktop. You just need to set the size/location of this component to be displayed at the top right of the desktop. You would then need to add a ComponentListener to the desktop pane to listen for the componentResized event. When this event is fired you would need to recalucate the location of the component to reset it to the top right.

Swing - GridBagLayout button adding mistake

I use this function to create tabs. When I want to add button "?" that will open the Wizard, this button appears at the right side of this JTable. How to edit this?
comp1 - "1. Dp/Drho", comp2 - "2. Df2/Drho", comp3 - "3. SDSS", comp4 - "4. Help". name1-4 - names of this tabs.
static protected JPanel allocateUniPane(Component comp1,Component comp2,Component comp3, Component comp4,
String name1, String name2, String name3, String name4){
JPanel resultPane = new JPanel();
GridBagLayout gridbagforUnionPane = new GridBagLayout();
GridBagConstraints cUnionPane = new GridBagConstraints();
resultPane.setLayout(gridbagforUnionPane);
cUnionPane.fill = GridBagConstraints.BOTH;
cUnionPane.anchor = GridBagConstraints.CENTER;
JButton showWizard = new JButton("?");
cUnionPane.weightx = 0.5;
cUnionPane.weighty = 0.5;
JTabbedPane jtp = new JTabbedPane();
jtp.addTab(name1, comp1);
jtp.addTab(name2, comp2);
jtp.addTab(name3, comp3);
jtp.addTab(name4, comp4);
cUnionPane.gridx = 0;
cUnionPane.gridy = 0;
resultPane.add(jtp,cUnionPane);
cUnionPane.fill = GridBagConstraints.NORTH;
cUnionPane.weightx = 0.5;
cUnionPane.gridx = 1;
cUnionPane.gridy = 0;
resultPane.add(showWizard,cUnionPane);
return resultPane;
}
You want the button to appear to be part of the tabbed pane. You can't use a GridBagLayout (or most other layouts) because they layout positions components in two dimensions on the panel.
Maybe the OverlayLayout will do what you want since it positions components in the third dimension. For example:
import java.awt.*;
import javax.swing.*;
import javax.swing.plaf.*;
public class TabbedPaneWithComponent
{
private static void createAndShowUI()
{
JPanel panel = new JPanel();
panel.setLayout( new OverlayLayout(panel) );
JTabbedPane tabbedPane = new JTabbedPane();
tabbedPane.add("1", new JTextField("one"));
tabbedPane.add("2", new JTextField("two"));
tabbedPane.setAlignmentX(1.0f);
tabbedPane.setAlignmentY(0.0f);
JCheckBox checkBox = new JCheckBox("Check Me");
checkBox.setOpaque( false );
checkBox.setAlignmentX(1.0f);
checkBox.setAlignmentY(0.0f);
panel.add( checkBox );
panel.add(tabbedPane);
JFrame frame = new JFrame("TabbedPane With Component");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( panel );
frame.setLocationByPlatform( true );
frame.setSize(400, 100);
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}

How to implement a JPanel that shows/hide content depending on its width?

I'm trying to implement a JPanel that displays more or less information depending on the available size.
Basically, the idea is have a default content like this:
That can shrinks to this when the space is reduced:
My code is like this:
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
class PanelDemo extends JPanel {
private final JLabel title = new JLabel();
private final JLabel counter1 = new JLabel("00");
private final JLabel counter1Label = new JLabel();
private final JLabel counter2 = new JLabel("00");
private final JLabel counter2Label = new JLabel();
/**
* Instantiates a new obs app cadre message bloc panel.
*/
public PanelDemo() {
this.setOpaque(false);
initGUI();
}
private final void initGUI() {
// 1°)
final MigLayout migLayout = new MigLayout(
"fillx, hidemode 2, debug",
"[growprio 0][]" //define 4 columns
);
setLayout(migLayout);
// 2°)
//
add(title, "spanx");
add(counter1, "newline");
add(counter1Label);
add(counter2);
add(counter2Label);
}
public static void main(String[] args) {
final JFrame jFrame = new JFrame("test 4");
jFrame.getContentPane().setLayout(new MigLayout("fillx, debug"));
final PanelDemo item1 = new PanelDemo();
item1.title.setText("Element 1");
item1.counter1Label.setText("First lbl");
item1.counter2Label.setText("Second lbl");
jFrame.getContentPane().add(item1, "growx, gpx 110");
final PanelDemo item2 = new PanelDemo();
item2.title.setText("Element 2");
item2.counter1Label.setText("First lbl");
item2.counter2Label.setText("Second lbl");
jFrame.getContentPane().add(item2, "growx, gpx 100");
jFrame.pack();
jFrame.setVisible(true);
} }
I tried to add a ComponentListener and override componentResized() to find when I could show/hide my secondary labels but I was not successful.
Does anybody know how to implement such a behaviour that goes well with MigLayout grow priorities?
Update1: I was thinking... what if I set the minimum width to counter1+label1, and the maximum size to counter2+label2 and then listen to resize operations and change the preferred size to either its minimum or its maximum. Would that mecanism work?
How about this:
public static JPanel panel(String name) {
JPanel panel = new JPanel(new MigLayout("insets 0, wrap 4, fillx, debug", "[][][shrink 200][shrink 200, grow 200]"));
panel.add(new JLabel(name), "spanx 4");
panel.add(new JLabel("00"));
panel.add(new JLabel("First lbl"));
panel.add(new JLabel("01"));
panel.add(new JLabel("Second lbl"));
return panel;
}
public static void main(String[] args) {
JPanel panel = new JPanel(new MigLayout("insets 10, gap 10, fillx, debug"));
panel.add(panel("Element 1"), "w (50% - 15)!");
panel.add(panel("Element 2"), "w (50% - 15)!");
JFrame frame = new JFrame();
frame.setContentPane(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
I had trouble getting the two main columns to resize equally; I had to do it by setting a width on the components rather than the columns. I'm not sure why that is.
I implemented an autohide mechanism with a LayoutCallback switching the visibility of the component depending on the width of the panel.
Here is an example:
MigLayout layout = new MigLayout("fill");
JPanel panel = new JPanel(layout);
JLabel label1 = new JLabel("Label 1");
label1.putClientProperty("autohide.width", 300);
JLabel label2 = new JLabel("Label 2");
label2.putClientProperty("autohide.width", 200);
panel.add(label1, "grow");
panel.add(label2, "grow");
layout.addLayoutCallback(new LayoutCallback() {
#Override
public void correctBounds(ComponentWrapper wrapper) {
JComponent component = (JComponent) wrapper.getComponent();
Number width = (Number) component.getClientProperty("autohide.width");
if (width != null) {
if (component.isVisible() && wrapper.getParent().getWidth() < width.intValue()) {
component.setVisible(false);
} else if (!component.isVisible() && wrapper.getParent().getWidth() > width.intValue()) {
component.setVisible(true);
}
}
}
});
Here the label1 is hidden when the width of the panel shrinks below 300 pixels, and label2 disappears when the width is less than 200 pixels.

Categories