How to make Java Swing components fill available space? - java

I cannot seem to get my Java Swing components to work together correctly.
What I want to do, is have a JPanel fill ALL the space available inside a JTabbedPane. At the moment, my setup is as follows:
public class Gui extends JFrame {
private final EventBus eventBus = EventBus.getInstance();
private final ToolkitUtil toolkitUtil;
private final Menu menu;
private final InfoBar infoBar;
private final JTabbedPane pane;
...
private void buildLayout() {
GridBagConstraints gbc = new GridBagConstraints();
setJMenuBar(menu);
add(pane, BorderLayout.CENTER);
add(infoBar, BorderLayout.SOUTH);
pane.addTab("Plugins", new PluginPanel());
}
}
public class PluginPanel extends JPanel {
private final JPanel modelPanel;
private final JPanel editorPanel;
public PluginPanel() {
setLayout(new GridBagLayout());
modelPanel = new JPanel(new GridBagLayout());
editorPanel = new JPanel(new GridBagLayout());
buildLayout();
}
private void buildLayout() {
GridBagConstraints gbc = new GridBagConstraints();
modelPanel.setBorder(BorderFactory.createTitledBorder("Models"));
editorPanel.setBorder(BorderFactory.createTitledBorder("Editors"));
gbc.gridx = 0;
gbc.fill = GridBagConstraints.BOTH;
modelPanel.add(new JLabel("test label"), gbc);
add(modelPanel, gbc);
gbc.gridx = 1;
add(editorPanel, gbc);
}
}
This creates a windows that is my desired size (dynamically proportional to the screen size, not included in above code). The tab panel that is placed in the center is expanded to fill all the space required, which is exactly what I want. But, the panels I add inside the tab panel are only as big as their content. If I add labels or anything, it only grows as big as the components. I want them to always be expanded to fill the tab panel.

The easiest way is to use a BorderLayout and put the component in the CENTER position.

Try setting the weights of the GridBagConstraints to non-zero values:
gbc.weightx = gbc.weighty = 1.0;

Set MinimumSize of your container to preferred size you want, then set ContentPane of container with your panel.
setMinimumSize(new Dimension(width,height));
setContentPane(new MyPanel());
This code works for all layouts.
Or simply call for your container:
setContentPane(new MyPanel());
This code works for BorderLayout or Free Design

Related

Java Swing trying to add a stationary JButton over a JScrollPane

I am trying to make a text editor with a button that appears at the bottom right of the editor regardless if you scroll up or down and appears over the text area
import javax.swing.*;
import java.awt.*;
public class Problem{
public static void main(String[] args){
//Setting up the frame
JFrame window = new JFrame();
window.setSize(600, 400);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Making the LayeredPane
JLayeredPane LP = new JLayeredPane();
LP.setLayout(new BorderLayout());
//Making the ScrollPane and JTextArea
JTextArea textArea = new JTextArea(100,50);
textArea.setText("Test Text");
JScrollPane back = new JScrollPane();
back.setViewportView(textArea);
//Making the panel that appears in the front of the text
JPanel front = new JPanel();
front.setLayout(null);
front.setBackground(new Color(0,0,0,0));
front.setOpaque(false);
JButton button = new JButton("test");
button.setBounds(200,200,50,20);
front.add(button);
LP.add(back,BorderLayout.CENTER);
LP.setLayer(back,0,0);
LP.add(front,BorderLayout.CENTER);
LP.setLayer(front,1,0);
window.add(LP);
window.setVisible(true);
}
}
I am seeing just the JButton with a white background, if I don't add the second layer "front" I see my back JScrollPane with the JTextArea
Caveat
I'm not a fan of this is idea. It's not a "common" UX concept that many desktop users would be presented with and there are a number of, arguably, better solutions which leverage the pre-existing experience of users.
This requires some "hacking" to get to work, so, there's no guarantee that it will work on all platforms or continue to work into the future.
Why doesn't it work?
This is a rather technical question which delves deep into the core of how Swing, and in particular, the JScrollPane work. Let's just say, I don't have the time or desire to dig into, but I know the JScrollPane is heavy optimised, which may be affecting the way in which anything which overlays it gets updated - or it could just be the way that the painting system works.
Runnable example...
This takes the idea by camickr (all credit to him), but instead of using a OverlayLayout, makes use of a GridBagLayout to position the button. Why? Because the GridBagLayout gives me more control over the position of the button - it's a personal thing.
import java.awt.*;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import javax.swing.*;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
JTextArea textArea = new JTextArea(40, 40);
try (Reader reader = new InputStreamReader(getClass().getResourceAsStream("/resources/StarWarsNewHope.txt"))) {
textArea.read(reader, "A long list");
} catch (IOException exp) {
exp.printStackTrace();
}
JButton button = new JButton("Am I in your way yet");
JPanel contentPane = new JPanel() {
#Override
public boolean isOptimizedDrawingEnabled() {
return false;
}
};
contentPane.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
// Change this to reposition the button some where else
gbc.anchor = GridBagConstraints.FIRST_LINE_END;
gbc.insets = new Insets(32, 32, 32, 32);
gbc.ipadx = 16;
gbc.ipady = 16;
contentPane.add(button, gbc);
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.fill = GridBagConstraints.BOTH;
JScrollPane scrollPane = new JScrollPane(textArea);
contentPane.add(scrollPane, gbc);
add(contentPane);
}
}
}
You should probably also look at How to Use Scroll Panes and the section on Providing Custom Decorations for some alternatives
Swing is designed/optimized to display/paint components in 2 dimensions. The vast majority of layout managers will make sure that the components don't overlap.
This means that you can't use a layout manager on your layered pane (if you want the components to overlap). Instead, you must manually set the size/location of components on each layer.
When you use a JLayeredPane the painting of components on each layer is managed so that the higher layer is painted last.
So your code might be changed to something like:
import java.awt.*;
import javax.swing.*;
public class Main
{
public static void main(String[] args)
{
JFrame window = new JFrame();
window.setSize(600, 400);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Making the LayeredPane
JLayeredPane LP = new JLayeredPane();
//Making the ScrollPane and JTextArea
JTextArea textArea = new JTextArea(20,40);
textArea.setText("Test Text");
textArea.setSize( textArea.getPreferredSize() );
JScrollPane back = new JScrollPane( textArea);
back.setSize( textArea.getSize() );
JButton button = new JButton("test");
button.setBounds(200,200,50,20);
LP.add(back, new Integer(0));
LP.add(button, new Integer(1));
window.add(LP);
window.setVisible(true);
}
}
There is one layout manager in the JDK, the OverlayLayout, which is designed to stack components on top of one another. However, even this layout manager does not paint components properly when the components overlap. The trick when using this layout manager is to override the isOptimizedDrawing() method of the panel using the layout manager to make sure all components are repainted all the time. In this case, make sure the bottom panel is always painted before the top panel.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
public class Main2
{
public static void main(String[] args)
{
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel contentPane = new JPanel()
{
#Override
public boolean isOptimizedDrawingEnabled()
{
return false;
}
};
contentPane.setLayout( new OverlayLayout(contentPane) );
JPanel top = new JPanel( new GridBagLayout() );
top.setBorder( new EmptyBorder(0, 0, 16, 16) );
top.setOpaque(false);
top.setAlignmentX(1.0f);
top.setAlignmentY(1.0f);
GridBagConstraints gbc = new GridBagConstraints();
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.anchor = GridBagConstraints.LAST_LINE_END;
JButton button = new JButton("test");
top.add(button, gbc);
contentPane.add(top);
//Making the ScrollPane and JTextArea
JTextArea textArea = new JTextArea(10,25);
textArea.setText("Test Text");
JScrollPane back = new JScrollPane( textArea);
back.setAlignmentX(1.0f);
back.setAlignmentY(1.0f);
contentPane.add(back);
window.add(contentPane);
window.pack();
window.setVisible(true);
}
}
The benefit of this approach is that the button will move as the frame is resized.
However, as a user I would still get annoyed with a button appearing over top of the text in my text area.
Edit:
If you really need components to overlap then I would suggest you could:
look at MadProgrammers solution to use a GridBagLayout. This approach gives far more control over the alignment of the components
check out the Overlap Layout which also provides more flexibility when aligning overlapping components
It should be noted that both above approaches may still require you to override the isOptimizedDrawEnabled(...) method to make sure components are painted properly. I am not aware of any layout manager the allows you to overlap components and works without this override.

How to place a panel containing three buttons in the upper left cell of a GridBagLayout?

I have a panel that contains three buttons. I want this panel to be placed in the upper left cell of a GridBagLayout.
My problem is that when I run the program the panel is not located in the upper left cell but it's in the middle of the layout. I have set both gridxand gridy to zero.
private JFrame frame;
private JMenuBar menuBar;
private JMenu menuFile;
private JMenuItem fileItem1;
private JMenuItem fileItem2;
private JPanel btnPanel;
private JButton btnRewind;
private JButton btnPlayPause;
private JButton btnFastForward;
private static boolean shouldFill = true;
private static boolean shouldWeightX = true;
private static boolean RIGHT_TO_LEFT = false;
public JPlayer() {
}
public void createAndShowGUI() {
frame = new JFrame();
frame.setTitle("JPlayer");
frame.setSize(500, 500);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
addComponentsToPane(frame.getContentPane());
frame.setVisible(true);
}
private void addComponentsToPane(Container pane) {
if(RIGHT_TO_LEFT) {
pane.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
}
pane.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
if(shouldFill) {
gbc.fill = GridBagConstraints.HORIZONTAL;
}
btnRewind = new JButton();
try {
Image imgRewind = ImageIO.read(getClass().getResource("../utils/images/rewind.png"));
btnRewind.setIcon(new ImageIcon(imgRewind));
btnRewind.setOpaque(true);
btnRewind.setContentAreaFilled(false);
btnRewind.setBorderPainted(false);
} catch(Exception e) {
e.printStackTrace();
}
btnPlayPause = new JButton();
try {
Image imgPlay = ImageIO.read(getClass().getResource("../utils/images/play.png"));
Image imgPause = ImageIO.read(getClass().getResource("../utils/images/pause.png"));
btnPlayPause.setIcon(new ImageIcon(imgPlay));
btnPlayPause.setOpaque(true);
btnPlayPause.setContentAreaFilled(false);
btnPlayPause.setBorderPainted(false);
} catch(Exception e) {
e.printStackTrace();
}
btnFastForward = new JButton();
try {
Image imgFastForward = ImageIO.read(getClass().getResource("../utils/images/fast_forward.png"));
btnFastForward.setIcon(new ImageIcon(imgFastForward));
btnFastForward.setOpaque(true);
btnFastForward.setContentAreaFilled(false);
btnFastForward.setBorderPainted(false);
} catch(Exception e) {
e.printStackTrace();
}
btnPanel = new JPanel();
btnPanel.add(btnRewind);
btnPanel.add(btnPlayPause);
btnPanel.add(btnFastForward);
btnPanel.setSize(new Dimension(40, 40));
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridx = 0;
gbc.gridy = 0;
JButton btn = new JButton("Some Button");
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 1;
c.gridy = 0;
pane.add(btnPanel, gbc);
pane.add(btn, c);
}
Try GridBagConstraints.anchor constraint that has default value as CENTER positioned.
Directly from documentation on How to Use GridBagLayout
If a component's display area is larger than the component itself, then you can specify whereabouts in the display area the component will be displayed by using the GridBagConstraints.anchor constraint.
The anchor constraint's values can be absolute (north, south, east, west, and so on), or orientation-relative (at start of page, at end of line, at the start of the first line, and so on), or relative to the component's baseline.
Note:
You don't need to use multiple instances of GridBagConstraints. Just create one and update the constraints before adding the component in the panel. In this way you can reuse the existing constraints that is common for all.
Don't forget to set weightx and weighty to use anchor constraints properly.
Directly from same documentation
weightx, weighty
Specifying weights is an art that can have a significant impact on the appearance of the components a GridBagLayout controls. Weights are used to determine how to distribute space among columns (weightx) and among rows (weighty); this is important for specifying resizing behavior.
Unless you specify at least one non-zero value for weightx or weighty, all the components clump together in the center of their container. This is because when the weight is 0.0 (the default), the GridBagLayout puts any extra space between its grid of cells and the edges of the container.

Swing : BoxLayout fill the entire JPanel

I am adding list of JTree items inside JPanel. I want the parent JPanel to have BoxLayout so that the tree can be added vertically one after another.
The parent JPanel is initialized using :
holder.setLayout(new BoxLayout(holder, BoxLayout.Y_AXIS));
holder.setMaximumSize(new java.awt.Dimension(32767, 24000));
holder.setMinimumSize(new java.awt.Dimension(600, 100));
holder.setPreferredSize(new java.awt.Dimension(600, 100));
The multiple JTree components are added inside :
holder.add(tree);
So i expect the JTree nodes to be occupying the entire width of my parent JPanel but somehow it is coming like this
So as you can see it coming in some portion of the parent JPanel. I want it to fill the entire parent Panel(width wise) and be aligned towards left.
EDIT
After trying the top-aligned approach mentioned by VGR I got this :
So the tree are not occupying the entire space still. And when i expand any tree then everything disappears.
I should have also mentioned this earlier that when the initilization of the parent panel(holder) is done in some other code like this
holder.setMaximumSize(new java.awt.Dimension(32767, 24000));
holder.setMinimumSize(new java.awt.Dimension(600, 100));
holder.setPreferredSize(new java.awt.Dimension(600, 100));
holder.setLayout(new java.awt.GridLayout(1, 0));
add(holder); // add to the top parent
This part is not reachable :( for me. I can only re-change the parent holder as per my requirement.
SSCCE after suggested changes from VGR. This is not compilable but i hope SSC.
public BasePanel() extends JPanel{
private javax.swing.JPanel holder;
private GridBagConstraints gbc;
private JPanel treesPanel;
BasePanel(){
init();
}
public init(){ can't access this method
holder.setMaximumSize(new java.awt.Dimension(32767, 25000));
holder.setMinimumSize(new java.awt.Dimension(600, 0));
holder.setPreferredSize(new java.awt.Dimension(600, 0));
holder.setLayout(new java.awt.GridLayout(1, 0));
add(holder);
}
public initTreeComponents(){ // i need to call this for each tree
this.holder.setLayout(new BorderLayout());
treesPanel = new JPanel(new GridBagLayout());
this.holder.add(treesPanel, BorderLayout.PAGE_START);
gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.VERTICAL;
gbc.anchor = GridBagConstraints.FIRST_LINE_START;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1;
}
public addTree(JTree tree){// to be called for each tree
treesPanel.add(tree,gbc);
}
I don't think BoxLayout makes child components fill the container. From the documentation:
… for a vertical layout, BoxLayout attempts to make all components in the column as wide as the widest component.
So your JTrees will all be the same width, but that doesn't guarantee they'll be as wide as the container.
Instead, I would use a GridBagLayout:
holder.setLayout(new GridBagLayout());
// etc.
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.anchor = GridBagConstraints.FIRST_LINE_START;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1;
holder.add(tree, gbc);
That will result in the JTrees being vertically centered. If you want them top-aligned, you should put a GridBagLayout panel inside another panel:
holder.setLayout(new BorderLayout());
JPanel treesPanel = new JPanel(new GridBagLayout());
holder.add(treesPanel, BorderLayout.PAGE_START);
// etc.
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.anchor = GridBagConstraints.FIRST_LINE_START;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1;
treesPanel.add(tree, gbc);
Try adding JTrees inside a JScrollPane, ie
holder.add(new JScrollPane(tree));

Java setBorder breaks component padding

When I set a border color to every item in a JPanel with GridBagLayout, the components collapse.
but when I remove the border off just one component, the padding stays as expected.
What am I doing wrong?
Border Setting:
setBorder(BorderFactory.createLineBorder(Color.decode("#"+Constants.Display.OPTIONS_BORDER_COLOR)));
JPanel:
public class OptionsPanel extends JPanel {
private AddMachineBtn addMachineBtn;
private SearchField searchField;
private SearchBtn searchBtn;
private GridBagConstraints gbc;
public OptionsPanel() {
init();
config();
build();
}
private void init() {
addMachineBtn = new AddMachineBtn("Add Machine");
searchField = new SearchField("Search...");
searchBtn = new SearchBtn("S");
gbc = new GridBagConstraints();
int i = Constants.Display.OPTIONS_PANEL_PADDING;
gbc.insets = new Insets(i, i, i, i);
}
private void config() {
setLayout(new GridBagLayout());
setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.decode("#"+Constants.Display.OPTIONS_BORDER_COLOR)));
setPreferredSize(new Dimension(0, Constants.Display.OPTIONS_PANEL_HEIGHT));
gbc.gridy = 0;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.anchor = gbc.LINE_START;
}
private void build() {
gbc.gridx = 0;
add(addMachineBtn, gbc);
gbc.weightx = 0;
gbc.gridx = 1;
add(searchField, gbc);
gbc.gridx = 2;
add(searchBtn, gbc);
}
}
I'm not sure about how it affects GridBagLayout, but "In general, when you want to set a border on a standard Swing component other than JPanel or JLabel, we recommend that you put the component in a JPanel and set the border on the JPanel."—setBorder(). There's a related example here.
Yes, layout has no affect to components' size. You may try to change layout (for example to FlowLayout) but situation will be the same.
Swing components obtains its border during initialization from Look'n'Feel.
Insert System.out.println(addMachineBtn.getBorder()); after addMachineBtn creation. You will see that the border already exists
javax.swing.plaf.BorderUIResource$CompoundBorderUIResource
This border provides its own insets for component, and when you replace border by another ones you loose its insets.
If it's really important to keep original components insets and replace border, try to imitate native Swing borders.
For example something like this:
addMachineBtn.setBorder(new CompoundBorder(new LineBorder(Color.red), new EmptyBorder(5, 17, 5, 17)));
Instead of LineBorder put border what you need, EmptyBorder keep the same, just correct insets as needed.
The fix to this was changing the following
setSize(new Dimension(w,h));
setMinimumSize(new Dimension(w,h));
setMaximumSize(new Dimension(w,h));
to
setPreferredSize(new Dimension(w,h));
setMinimumSize(new Dimension(w,h));
setMaximumSize(new Dimension(w,h));

BoxLayout misunderstanding strut

I'm prgramming a simple input diagram in Swing. I use boxLayout to create a simple GUI of user input. Problem is that creating a horizontal strut between the JPanel of all the labels and the JPanel of the JTextFields causes the whole panel to shift downwards (weird) this is the whole panel:
private JPanel secondCard() {
//main panel. set the boxlayout
secondCard = new JPanel();
secondCard.setLayout(new BoxLayout(secondCard,BoxLayout.Y_AXIS));
// create vertical strut for looks
secondCard.add(Box.createVerticalStrut(20));
// create title. center it.
JLabel title = new JLabel("Configure main network parameters ");
title.setAlignmentX(CENTER_ALIGNMENT);
secondCard.add(title);
// create vertical strut for looks
secondCard.add(Box.createVerticalStrut(20));
// create panel for the description labels
JPanel labelPanel = new JPanel();
labelPanel.setLayout(new BoxLayout(labelPanel,BoxLayout.Y_AXIS));
labelPanel.setAlignmentX(LEFT_ALIGNMENT);
JLabel inPut =new JLabel("number of inputs");
inPut.setAlignmentX(LEFT_ALIGNMENT);
labelPanel.add(inPut);
inPut =new JLabel("number of outputs");
inPut.setAlignmentX(LEFT_ALIGNMENT);
labelPanel.add(inPut);
inPut =new JLabel("number of layers");
inPut.setAlignmentX(LEFT_ALIGNMENT);
labelPanel.add(inPut);
JPanel textFieldPanel = new JPanel();
textFieldPanel.setLayout(new BoxLayout(textFieldPanel,BoxLayout.Y_AXIS));
textFieldPanel.setAlignmentX(LEFT_ALIGNMENT);
JTextField inputTextField = new JTextField();
inputTextField.setAlignmentX(LEFT_ALIGNMENT);
textFieldPanel.add(inputTextField);
inputTextField.setMinimumSize(new Dimension(0,0));
inputTextField = new JTextField();
inputTextField.setAlignmentX(LEFT_ALIGNMENT);
textFieldPanel.add(inputTextField);
inputTextField.setMinimumSize(new Dimension(0,0));
inputTextField = new JTextField();
inputTextField.setAlignmentX(LEFT_ALIGNMENT);
textFieldPanel.add(inputTextField);
inputTextField.setMinimumSize(new Dimension(0,0));
textFieldPanel.setMaximumSize(new Dimension(50, labelPanel.getMaximumSize().height));
JPanel inputPanel = new JPanel();
inputPanel.setLayout(new BoxLayout(inputPanel,BoxLayout.X_AXIS));
inputPanel.setAlignmentX(CENTER_ALIGNMENT);
inputPanel.add(labelPanel);
//this is the problem strut!! it causes inputPanel to shift downwards
inputPanel.add(Box.createHorizontalStrut(20));
inputPanel.add(textFieldPanel);
secondCard.add(inputPanel);
return secondCard;
}
without the strut it looks like:
With strut it looks like (I know I suck at picture editing):
You are adding a Box strut to a BoxLayout.
As the javadoc states, createHorizontalStrut(int width):
Creates an invisible, fixed-width component. In a horizontal box, you
typically use this method to force a certain amount of space between
two components. In a vertical box, you might use this method to force
the box to be at least the specified width. The invisible component
has no height unless excess space is available, in which case it takes
its share of available space, just like any other component that has
no maximum height.
As such, it is filling the height between your title JLabel and the bottom of the JPanel.
You might want to consider using Box.createRigidArea(new Dimension(20, height)) instead, where height could be specified or set to the height of labelPanel.
Or, you could reconsider the layout for your JPanel - take a look at the visual guide.
For future reference, if you cannot make sense of your Swing layout, try putting adding a coloured LineBorder to the JComponents you're unsure of. In this case, the Box struts are not JComponents but Components, so you'd have to put them into a JPanel, but this would at least have shown you what space each component was taking up in your top-level JPanel.
use Cardlayout for wizard logics
put JLabel(Configure ...., JLabel.CENTER) to the BorderLayout.NORTH
put JPanel with JButtons to the BorderLayout.SOUTH
put JPanel with SpringLayout, GridLayout, or GridBagLayout to the BorderLayout.CENTER
Top-Level Container have got implemened BorderLayout by default, then there no reason to re_define BorderLayout
above mentioned steps are called NestedLayout
alternative are put all JComponents by using GridBagLayout, SpringLayout or todays MigLayout to the one JPanel, but why bothering
Example of a nested layout, one using BorderLayout, FlowLayout (JPanel's default), and GridBagLayout:
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.util.HashMap;
import java.util.Map;
import javax.swing.*;
public class LayoutFoo {
private static final String TITLE = "Configure Main Foobar Parameters";
private static final String[] LABEL_TEXTS = {
"Number of Spams", "Number of Frapzats", "Number of Zignuts"
};
private static final int TEXTFIELD_SIZE = 10;
private static final Insets WEST_INSETS = new Insets(5, 5, 5, 10);
private static final Insets EAST_INSETS = new Insets(5, 10, 5, 5);
private static final int EB_GAP = 5;
private Map<String, JTextField> textFieldMap = new HashMap<String, JTextField>();
public JPanel getConfigFooPanel() {
JPanel textFieldPanel = new JPanel(new GridBagLayout());
for (int i = 0; i < LABEL_TEXTS.length; i++) {
addTextAndField(textFieldPanel, LABEL_TEXTS[i], i);
}
int blVertGap = 20;
JPanel borderLayoutPanel = new JPanel(new BorderLayout(0, blVertGap));
borderLayoutPanel.setBorder(BorderFactory.createEmptyBorder(EB_GAP, EB_GAP,
EB_GAP, EB_GAP));
JLabel titleLabel = new JLabel(TITLE, JLabel.CENTER);
borderLayoutPanel.add(titleLabel, BorderLayout.PAGE_START);
borderLayoutPanel.add(textFieldPanel, BorderLayout.CENTER);
JPanel outerWrapperFlowPanel = new JPanel();
outerWrapperFlowPanel.add(borderLayoutPanel);
return outerWrapperFlowPanel;
}
public String getFieldText(String labelText) {
JTextField field = textFieldMap.get(labelText);
if (field == null) {
return ""; // ?? throw exception
} else {
return field.getText();
}
}
private void addTextAndField(JPanel panel, String text, int i) {
JLabel label = new JLabel(text, JLabel.LEFT);
JTextField textField = new JTextField(TEXTFIELD_SIZE);
textFieldMap.put(text, textField);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = i;
gbc.gridwidth = 1;
gbc.gridheight = 1;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.anchor = GridBagConstraints.WEST;
gbc.insets = WEST_INSETS;
panel.add(label, gbc);
gbc.gridx = 1;
gbc.anchor = GridBagConstraints.EAST;
gbc.insets = EAST_INSETS;
panel.add(textField, gbc);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("LayoutFoo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new LayoutFoo().getConfigFooPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Categories