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.
Related
I'd like to have x JTables on top of each other acting like one JTable. I have created x separate JScollPanes - one for each table and inserted them all into one JPanel (panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));).
I only show the header for the top most table. In order to achieve them scrolling horizontally in unison, I have used here.
I need two more tasks left to achieve the desired result of it looking like one big JTable.
I'd like there to only be one vertical scroll bar? How to achieve this?
I'd like all tables to share the same TableColumnModel as the top most table (which is the only one that shows the header) so if a column is moved via drag drop header, all tables reflect the change...
In case anyone is wondering, I previously tried to add each JTable to a JPanel and then add each JPanel to one JScrollPane. The problem with that solution is that if one of the JTable's has many entries, a vertical scroll bar won't appear to show all the entries....
Based on this question and pictures from your other questions I might have an approach, although it is a bit of a hack.
The approach:
Create multiple tables and add them to a JScrollPane. Add each scroll pane to the panel using the BoxLayout
The first scroll pane will contain and empty table so only the table header will be visible in the scroll pane.
The last scroll pane will display the JTable and the horizontal scrollbar.
Any scroll pane between the first and last will only display the JTable.
The code uses a custom ScrollablePanel. This panel will force the width of the panel to be equal to the width of the viewport. This will in turn force the horizontal scroll bars of each scroll pane to be active. Each horizontal scrollbar shares the same model, so even though only one scrollbar is visible all tables will scroll at the same time.
Check out Scrollable Panel for the code to download.
Here the code:
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
public class TableSharedHeader2 extends JPanel
{
private JTable table1;
private JTable table2;
private JPanel tablePanel;
TableSharedHeader2()
{
setLayout( new BorderLayout() );
// Only the Table Header is displayed
JTable table0 = new JTable( 0, 10);
table0.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );
table0.setPreferredScrollableViewportSize(table0.getPreferredSize());
JScrollPane scrollPane0 = new JScrollPane( table0 );
scrollPane0.setVerticalScrollBarPolicy( ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER );
// Only the JTable is displayed
table1 = new JTable(5, 10);
table1.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );
table1.setTableHeader( null );
table1.setPreferredScrollableViewportSize(table1.getPreferredSize());
JScrollPane scrollPane1 = new JScrollPane( table1 );
scrollPane1.setVerticalScrollBarPolicy( ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER );
// The JTable and the horizontal scrollbar is displayed.
table2 = new JTable(3, 10);
table2.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );
table2.setTableHeader( null );
System.out.println(table0.getTableHeader());
table2.setPreferredScrollableViewportSize(table2.getPreferredSize());
JScrollPane scrollPane2 = new JScrollPane( table2 );
scrollPane2.setVerticalScrollBarPolicy( ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER );
scrollPane2.setHorizontalScrollBarPolicy( ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS );
// share the column model with the last two tables
table1.setColumnModel( table0.getColumnModel() );
table2.setColumnModel( table0.getColumnModel() );
// share the scrollbar model with the last two scrollbars
scrollPane1.getHorizontalScrollBar().setModel( scrollPane0.getHorizontalScrollBar().getModel());
scrollPane2.getHorizontalScrollBar().setModel( scrollPane0.getHorizontalScrollBar().getModel());
// hide the scrollbars of the first two tables.
scrollPane0.getHorizontalScrollBar().setPreferredSize( new Dimension(0, 0) );
scrollPane1.getHorizontalScrollBar().setPreferredSize( new Dimension(0, 0) );
// add components to the panel
tablePanel = new JPanel();
ScrollablePanel tablePanel = new ScrollablePanel();
tablePanel.setScrollableWidth( ScrollablePanel.ScrollableSizeHint.FIT );
tablePanel.setLayout( new BoxLayout(tablePanel, BoxLayout.Y_AXIS) );
tablePanel.add( scrollPane0 );
tablePanel.add( new JLabel("First Label") );
tablePanel.add( scrollPane1 );
tablePanel.add( new JLabel("Second Label") );
tablePanel.add( scrollPane2 );
JScrollPane scrollPane = new JScrollPane( tablePanel );
scrollPane.setHorizontalScrollBarPolicy( ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER );
add( scrollPane );
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("TableSharedHeader2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TableSharedHeader2());
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}
Here is the code solution after great help and guidance from camickr.
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
public class TableSharedHeader2 extends JPanel
{
private JTable table1;
private JTable table2;
private JPanel tablePanel;
TableSharedHeader2()
{
setLayout( new BorderLayout() );
// Only the Table Header is displayed
JTable table0 = new JTable( 0, 10);
table0.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );
table0.setPreferredScrollableViewportSize(table0.getPreferredSize());
JScrollPane scrollPane0 = new JScrollPane( table0 );
scrollPane0.setVerticalScrollBarPolicy( ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER );
// Only the JTable is displayed
table1 = new JTable(5, 10);
table1.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );
table1.setTableHeader( null );
table1.setPreferredScrollableViewportSize(table1.getPreferredSize());
JScrollPane scrollPane1 = new JScrollPane( table1 );
scrollPane1.setVerticalScrollBarPolicy( ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER );
// The JTable and the horizontal scrollbar is displayed.
table2 = new JTable(60, 10);
table2.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );
table2.setTableHeader( null );
System.out.println(table0.getTableHeader());
table2.setPreferredScrollableViewportSize(table2.getPreferredSize());
JScrollPane scrollPane2 = new JScrollPane( table2 );
scrollPane2.setVerticalScrollBarPolicy( ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER );
scrollPane2.setHorizontalScrollBarPolicy( ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER );
// share the column model with the last two tables
table1.setColumnModel( table0.getColumnModel() );
table2.setColumnModel( table0.getColumnModel() );
// share the scrollbar model with the last two scrollbars
scrollPane1.getHorizontalScrollBar().setModel( scrollPane0.getHorizontalScrollBar().getModel());
scrollPane2.getHorizontalScrollBar().setModel( scrollPane0.getHorizontalScrollBar().getModel());
// hide the scrollbars of the first two tables.
scrollPane0.getHorizontalScrollBar().setPreferredSize( new Dimension(0, 0) );
scrollPane1.getHorizontalScrollBar().setPreferredSize( new Dimension(0, 0) );
// add components to the panel
tablePanel = new JPanel();
ScrollablePanel tablePanel = new ScrollablePanel();
tablePanel.setScrollableWidth( ScrollablePanel.ScrollableSizeHint.FIT );
//changed this to stretch for Vertical Scroll Bar to appear if frame is resized and data can not fit in viewport
tablePanel.setScrollableHeight( ScrollablePanel.ScrollableSizeHint.STRETCH );
tablePanel.setLayout( new BoxLayout(tablePanel, BoxLayout.Y_AXIS) );
tablePanel.add( new JLabel("First Label") );
tablePanel.add( scrollPane1 );
tablePanel.add( new JLabel("Second Label") );
tablePanel.add( scrollPane2 );
JScrollPane scrollPane = new JScrollPane( tablePanel );
JScrollBar bar = scrollPane2.getHorizontalScrollBar();
//this removes mouse wheel listeners from all the inner scrollpanes and
//allows the main scrollpane (scrollPane) to react to mousewheel
scrollPane0.removeMouseWheelListener(scrollPane0.getMouseWheelListeners()[0]);
scrollPane1.removeMouseWheelListener(scrollPane1.getMouseWheelListeners()[0]);
scrollPane2.removeMouseWheelListener(scrollPane2.getMouseWheelListeners()[0]);
// Add header to top of border layout
add(scrollPane0,BorderLayout.PAGE_START);
//add main tablePanel which has JTables (no headers) and labels to body of border layout
add( scrollPane,BorderLayout.CENTER );
//add bottom scollpane (scrollpane2) scroll bar to bottom of border layout
add(bar,BorderLayout.PAGE_END);
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("TableSharedHeader2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TableSharedHeader2());
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}
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.
I am using MigLayout (and I really like it). But I have a problem with Labels in front of a JTextArea.
I have read about the "baseline" keyword. But that does not work in combination with "grow".
Here is an example that shows the problem.
I expected the label to be aligned at the top (at the same location as the first line of the JTextArea).
Any ideas?
public class MigRunner {
public static void main( String[] args ) {
SwingUtilities.invokeLater( new Runnable() {
#Override
public void run() {
new MigRunner().run();
}
} );
}
#UiThread
private void run() {
JFrame frame = new JFrame();
Container contentPane = frame.getContentPane();
contentPane.setLayout( new MigLayout("wrap 2, fill, debug", "[][grow]", "[grow]") );
{
JLabel name = new JLabel( "Description" );
contentPane.add( name, "baseline" );
JTextArea textArea = new JTextArea();
JScrollPane scrollPane = new JScrollPane( textArea );
contentPane.add( scrollPane, "grow, baseline" );
name.setLabelFor( textArea );
}
frame.setDefaultCloseOperation( WindowConstants.DISPOSE_ON_CLOSE );
frame.setSize( 400, 300 );
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
}
Maybe you need the align contraint:
JLabel name = new JLabel("Description");
contentPane.add(name, "aligny top");
I didn't saw the 3 pixel gap between the baselines of the texts until Jeremias' comment. Well I don't have a nice solution for this, but here is an additional idea to Jeremias "gaptop 3" solution:
JTextArea name = new JTextArea("Description");
name.setEditable(false);
contentPane.add(new JScrollPane(name), "aligny top");
I'm attempting to create a program that allows the user to click a button to place something in the JPanel and allowing them to move this item around. I have already found a good layout to use to allow the moving components (see this link). However, I'm just curious the best way to create a layout like this? My hope is to have something like this:
How can I accomplish this? Would I want to use two JPanel's or something else?
The main panel (or the window content pane) would have to have a BorderLayout as the layout manager.
Then, the buttons panel would be added to BorderLayout.WEST and the drag panel to BorderLayout.CENTER.
There is a Visual Guide to swing layout managers.
Try to use JSplitPane:
Here is a code example:
class SplitPane extends JFrame {
private JSplitPane splitPaneV;
private JSplitPane splitPaneH;
private JPanel panel1;
private JPanel panel2;
private JPanel panel3;
public SplitPane(){
setTitle( "Split Pane Application" );
setBackground( Color.gray );
JPanel topPanel = new JPanel();
topPanel.setLayout( new BorderLayout() );
getContentPane().add( topPanel );
// Create the panels
createPanel1();
createPanel2();
createPanel3();
// Create a splitter pane
splitPaneV = new JSplitPane( JSplitPane.VERTICAL_SPLIT );
topPanel.add( splitPaneV, BorderLayout.CENTER );
splitPaneH = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT );
splitPaneH.setLeftComponent( panel1 );
splitPaneH.setRightComponent( panel2 );
splitPaneV.setLeftComponent( splitPaneH );
splitPaneV.setRightComponent( panel3 );
}
public void createPanel1(){
panel1 = new JPanel();
panel1.setLayout( new BorderLayout() );
// Add some buttons
panel1.add( new JButton( "North" ), BorderLayout.NORTH );
panel1.add( new JButton( "South" ), BorderLayout.SOUTH );
panel1.add( new JButton( "East" ), BorderLayout.EAST );
panel1.add( new JButton( "West" ), BorderLayout.WEST );
panel1.add( new JButton( "Center" ), BorderLayout.CENTER );
}
public void createPanel2(){
panel2 = new JPanel();
panel2.setLayout( new FlowLayout() );
panel2.add( new JButton( "Button 1" ) );
panel2.add( new JButton( "Button 2" ) );
panel2.add( new JButton( "Button 3" ) );
}
public void createPanel3(){
panel3 = new JPanel();
panel3.setLayout( new BorderLayout() );
panel3.setPreferredSize( new Dimension( 400, 100 ) );
panel3.setMinimumSize( new Dimension( 100, 50 ) );
panel3.add( new JLabel( "Notes:" ), BorderLayout.NORTH );
panel3.add( new JTextArea(), BorderLayout.CENTER );
}
public static void main( String args[] ){
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {}
// Create an instance of the test application
SplitPane mainFrame = new SplitPane();
mainFrame.pack();
mainFrame.setVisible( true );
}
}
You can play with splitPaneH.setOneTouchExpandable true/false
You can confugure divider location for both like:
Toolkit tk = Toolkit.getDefaultToolkit();
Dimension d = tk.getScreenSize();
int width = d.width;
int height = d.height;
spane.setDividerLocation((width*3)/4);
spanex.setDividerLocation(width/4);
I am working on a project with JTabbedPane
When I click TAB2, it shows the PANEL 2. Done
PANEL 2 consist of a JButton "Next" that will switch to PANEL 2.1 and JButton "Previous" to
switch it back to PANEL 2 while still in the TAB 2.
So, it is a Card Layout inside Tab2?
Thanks for helping!
-----------------------------
TAB 1 | TAB 2 | TAB 3 |
-----------------------------
-
-
PANEL 2 -
-
-
-
-
"Previous" "NEXT" -
========================== =
You just need to insert a JPanel in the tab and set its layout as CardLayout. So, inside each "card" you will insert a new JPanel. Here is an example:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Foo extends JFrame {
public Foo() {
setTitle( "Tabs and Cards" );
setSize( 400, 400 );
setDefaultCloseOperation( EXIT_ON_CLOSE );
JTabbedPane tabbedPane = new JTabbedPane();
// needs to be final to be accessed inside the event handlers
final JPanel tab1 = new JPanel();
final JPanel tab2 = new JPanel();
tab2.setLayout( new CardLayout() );
tabbedPane.addTab( "Tab 1", tab1 );
tabbedPane.addTab( "Tab 2", tab2 );
JPanel tab21 = new JPanel();
tab21.add( new JLabel( "2.1" ) );
JPanel tab22 = new JPanel();
tab22.add( new JLabel( "2.2" ) );
JPanel tab23 = new JPanel();
tab23.add( new JLabel( "2.3" ) );
tab2.add( tab21 );
tab2.add( tab22 );
tab2.add( tab23 );
JButton btnToTab22 = new JButton( "Next!" );
btnToTab22.addActionListener( new ActionListener(){
#Override
public void actionPerformed( ActionEvent evt ) {
// gets the layout, casts it and call next to go to the next card
( ( CardLayout ) tab2.getLayout() ).next( tab2 );
}
});
tab21.add( btnToTab22 );
JButton btnToTab23 = new JButton( "Next!" );
btnToTab23.addActionListener( new ActionListener(){
#Override
public void actionPerformed( ActionEvent evt ) {
( ( CardLayout ) tab2.getLayout() ).next( tab2 );
}
});
tab22.add( btnToTab23 );
add( tabbedPane, BorderLayout.CENTER );
setVisible( true );
}
public static void main( String[] args ) {
new Foo();
}
}
I didn't commented the code because is not so complicated, but I think that you will understand easily. Take a look at the documentation.