I have written this code
package test;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import javax.swing.*;
import javax.swing.GroupLayout.Alignment;
public class MainFrame extends JFrame
{
private int levels;
private int slots;
private JLabel labelShowLevel;
private JFormattedTextField textShowLevel;
private JButton buttonShowLevel ;
private JLabel labelAddEntity ;
private JFormattedTextField textAddEntity ;
private JButton buttonAddEntity ;
private JComboBox cb;
private JLabel labelRemoveEntity ;
private JFormattedTextField textRemoveEntity ;
private JButton buttonRemoveEntity ;
private JLabel labelSearchEntity ;
private JFormattedTextField textSearchEntity ;
private JButton buttonSearchEntity ;
private JLabel labelEmptySlots ;
private JButton buttonEmptySlots ;
private JLabel levelDispaly;
private JLabel totalLevels;
public MainFrame(int levels, int slots)
{
this.levels = levels;
this.slots = slots;
getContentPane().add( CreatPanel(), BorderLayout.EAST);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setPreferredSize(new Dimension(1000,500));
this.revalidate();
this.repaint();
this.pack();
this.setVisible(true);
}
JPanel CreatPanel()
{
JPanel panel = new JPanel();
labelShowLevel = new JLabel("Display Level");
labelAddEntity = new JLabel("Enter new car/motorbike");
labelRemoveEntity = new JLabel("Exit car/motorbike");
labelSearchEntity = new JLabel("Find car/motorbike");
labelEmptySlots = new JLabel("Get total empty slots");
textShowLevel = new JFormattedTextField();
textAddEntity = new JFormattedTextField();
textRemoveEntity = new JFormattedTextField();
textSearchEntity = new JFormattedTextField();
textShowLevel.setPreferredSize(new Dimension(100, HEIGHT));
buttonShowLevel = new JButton("Show");
buttonAddEntity = new JButton("Enter");
buttonRemoveEntity= new JButton("Exit");
buttonSearchEntity = new JButton("Search");
buttonEmptySlots = new JButton("Find");
Font font = new Font("sans comic", Font.ITALIC, 18);
levelDispaly = new JLabel("Now Displaying Level 0");
levelDispaly.setFont(font);
totalLevels = new JLabel("Total Levels:"+ this.levels+" Total slots per level:"+this.slots);
String[] items = { "Car", "Motorbike" };
cb = new JComboBox(items);
cb.setSelectedItem(items[0]);
GroupLayout layout = new GroupLayout(panel);
panel.setLayout(layout);
layout.setAutoCreateGaps(true);
layout.setAutoCreateContainerGaps(true);
GroupLayout.SequentialGroup hGroup = layout.createSequentialGroup();
hGroup.addGroup(layout.createParallelGroup().
addComponent(labelShowLevel).addComponent(labelAddEntity).addComponent(labelRemoveEntity).addComponent(labelSearchEntity).addComponent(labelEmptySlots).addComponent(levelDispaly).addComponent(totalLevels));
hGroup.addGroup(layout.createParallelGroup().
addComponent(textShowLevel).addComponent(textAddEntity).addComponent(cb).addComponent(textRemoveEntity).addComponent(textSearchEntity));
hGroup.addGroup(layout.createParallelGroup().
addComponent(buttonShowLevel).addComponent(buttonAddEntity).addComponent(buttonRemoveEntity).addComponent(buttonSearchEntity).addComponent(buttonEmptySlots));
layout.setHorizontalGroup(hGroup);
layout.linkSize(SwingConstants.HORIZONTAL, buttonShowLevel, buttonAddEntity,buttonRemoveEntity,buttonSearchEntity,buttonEmptySlots);
// Create a sequential group for the vertical axis.
GroupLayout.SequentialGroup vGroup = layout.createSequentialGroup();
vGroup.addGroup(layout.createParallelGroup(Alignment.BASELINE).
addComponent(labelShowLevel).addComponent(textShowLevel).addComponent(buttonShowLevel));
vGroup.addGroup(layout.createParallelGroup(Alignment.BASELINE).
addComponent(labelAddEntity).addComponent(textAddEntity));
vGroup.addGroup(layout.createParallelGroup(Alignment.BASELINE).
addComponent(cb).addComponent(buttonAddEntity));
vGroup.addGroup(layout.createParallelGroup(Alignment.BASELINE).
addComponent(labelRemoveEntity).addComponent(textRemoveEntity).addComponent(buttonRemoveEntity));
vGroup.addGroup(layout.createParallelGroup(Alignment.BASELINE).
addComponent(labelSearchEntity).addComponent(textSearchEntity).addComponent(buttonSearchEntity));
vGroup.addGroup(layout.createParallelGroup(Alignment.BASELINE).
addComponent(labelEmptySlots).addComponent(buttonEmptySlots));
vGroup.addGroup(layout.createParallelGroup(Alignment.BASELINE).
addComponent(levelDispaly));
vGroup.addGroup(layout.createParallelGroup(Alignment.BASELINE).
addComponent(totalLevels));
layout.setVerticalGroup(vGroup);
return panel;
}
public static void main(String args[])
{
java.awt.EventQueue.invokeLater(new Runnable() {
public void run()
{
try
{
UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
}
catch (Exception ex) {
ex.printStackTrace();
}
(new MainFrame(5,5)).setVisible(true);
}
});
}
}
and the result is
What I want is to center the last two labels (totalLevels and levelDispaly) and make them take the three columns. I did many trials and faild.
Note that the left side of the pane is empty because I have deleted the unnecessary parts of the code just to concentrate on the problem.
You were close - you fell on a caveat called still developing intuition for GroupLayout. Some people never leave this limbo :)
Jokes aside, here is your MCVE with a few changes:
public class MainFrame extends JFrame {
private int levels;
private int slots;
private JLabel labelShowLevel;
private JFormattedTextField textShowLevel;
private JButton buttonShowLevel;
private JLabel labelAddEntity;
private JFormattedTextField textAddEntity;
private JButton buttonAddEntity;
private JComboBox cb;
private JLabel labelRemoveEntity;
private JFormattedTextField textRemoveEntity;
private JButton buttonRemoveEntity;
private JLabel labelSearchEntity;
private JFormattedTextField textSearchEntity;
private JButton buttonSearchEntity;
private JLabel labelEmptySlots;
private JButton buttonEmptySlots;
private JLabel levelDispaly;
private JLabel totalLevels;
public MainFrame(int levels, int slots) {
this.levels = levels;
this.slots = slots;
getContentPane().add(CreatPanel());
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.pack();
this.setVisible(true);
}
JPanel CreatPanel() {
JPanel panel = new JPanel();
labelShowLevel = new JLabel("Display Level");
labelAddEntity = new JLabel("Enter new car/motorbike");
labelRemoveEntity = new JLabel("Exit car/motorbike");
labelSearchEntity = new JLabel("Find car/motorbike");
labelEmptySlots = new JLabel("Get total empty slots");
textShowLevel = new JFormattedTextField();
textAddEntity = new JFormattedTextField();
textRemoveEntity = new JFormattedTextField();
textSearchEntity = new JFormattedTextField();
textShowLevel.setPreferredSize(new Dimension(100, HEIGHT));
buttonShowLevel = new JButton("Show");
buttonAddEntity = new JButton("Enter");
buttonRemoveEntity = new JButton("Exit");
buttonSearchEntity = new JButton("Search");
buttonEmptySlots = new JButton("Find");
Font font = new Font("sans comic", Font.ITALIC, 18);
levelDispaly = new JLabel("Now Displaying Level 0");
levelDispaly.setFont(font);
totalLevels = new JLabel("Total Levels:"+ this.levels + " Total slots per level:"
+ this.slots);
String[] items = {"Car", "Motorbike"};
cb = new JComboBox(items);
cb.setSelectedItem(items[0]);
GroupLayout layout = new GroupLayout(panel);
panel.setLayout(layout);
layout.setAutoCreateGaps(true);
layout.setAutoCreateContainerGaps(true);
layout.linkSize(SwingConstants.HORIZONTAL, buttonShowLevel, buttonAddEntity, buttonRemoveEntity, buttonSearchEntity, buttonEmptySlots);
//#formatter:off
// Horizontal
GroupLayout.ParallelGroup hGroup = layout.createParallelGroup(Alignment.CENTER); // Will align the labels the way you wanted
hGroup.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup()
.addComponent(labelShowLevel)
.addComponent(labelAddEntity)
.addComponent(labelRemoveEntity)
.addComponent(labelSearchEntity)
.addComponent(labelEmptySlots))
.addGroup(layout.createParallelGroup()
.addComponent(textShowLevel)
.addComponent(textAddEntity)
.addComponent(cb)
.addComponent(textRemoveEntity)
.addComponent(textSearchEntity))
.addGroup(layout.createParallelGroup()
.addComponent(buttonShowLevel)
.addComponent(buttonAddEntity)
.addComponent(buttonRemoveEntity)
.addComponent(buttonSearchEntity)
.addComponent(buttonEmptySlots)));
hGroup.addComponent(levelDispaly);
hGroup.addComponent(totalLevels);
layout.setHorizontalGroup(hGroup);
// Vertical
GroupLayout.SequentialGroup vGroup = layout.createSequentialGroup();
vGroup.addGroup(layout.createParallelGroup()
.addComponent(labelShowLevel)
.addComponent(textShowLevel)
.addComponent(buttonShowLevel));
vGroup.addGroup(layout.createParallelGroup()
.addComponent(labelAddEntity)
.addComponent(textAddEntity));
vGroup.addGroup(layout.createParallelGroup()
.addComponent(cb)
.addComponent(buttonAddEntity));
vGroup.addGroup(layout.createParallelGroup()
.addComponent(labelRemoveEntity)
.addComponent(textRemoveEntity)
.addComponent(buttonRemoveEntity));
vGroup.addGroup(layout.createParallelGroup()
.addComponent(labelSearchEntity)
.addComponent(textSearchEntity)
.addComponent(buttonSearchEntity));
vGroup.addGroup(layout.createParallelGroup()
.addComponent(labelEmptySlots)
.addComponent(buttonEmptySlots));
vGroup.addGroup(layout.createParallelGroup()
.addComponent(levelDispaly));
vGroup.addGroup(layout.createParallelGroup()
.addComponent(totalLevels));
layout.setVerticalGroup(vGroup);
//#formatter:on
return panel;
}
public static void main(String args[]) {
EventQueue.invokeLater(() -> new MainFrame(5, 5));
}
}
Your problem was in the horizontal group. You restricted your labels to be aligned with the left column. As a general rule of thumb, if you want components which are unrestricted (free to be aligned) in a certain direction, then you need to add another "level" of groups in that direction's hierarchy.
Specifically, after removing the 2 labels from your horizontal code, you are left with a sequential group (hGroup in your case) which has parallel groups in it. Since the 2 labels are not to be aligned with these groups, they must be added to a sequential group that is not hGroup. That means that if hGroup is sequential, it will have a single "child" parallel group, which will have under it the new sequential group (that replaces hGroup) along with the 2 labels:
hGroup (seq.)
p (par.)
s (Seq.)
p1
p2
p3
label1
label2
(not showing the components under p1-p3.)
However, since hGroup now has only 1 child, you can just remove this redundant top-level sequential group and make hGroup that single parallel group. Remember that both your horizontal and vertical groups can be either one of sequential or parallel groups. Don't restrict yourself to having both directions sequential since that just adds redundant groups (it will still work):
hGroup (par.)
s (Seq.)
p1
p2
p3
label1
label2
The following are general thinking patterns that can help you with GroupLayout. Do note that there are many ways one can think about these and come up with alternative explanations. After a while with Grouplayout this will become completely intuitive.
Choosing the right type of parent group
If you want to know if your vertical/horizontal group should be sequential or parallel, just look at the "governing direction". The "governing direction" is the direction in which you can definitively tell the sequence of the components at the highest level.
In your case, let's look at vertical group. When looking from top to bottom, you can tell definitively the order of components (or groups thereof) from top to bottom, but not from left to right because the last 2 labels don't have a definitive left to right order with respect to the other components - these 2 labels are determined by alignment. Then
Vertical group && Vertical governing direction == Sequential group
For the horizontal group, again you can only tell the top to bottom order:
Horizontal group && Vertical governing direction == Parallel group
If there is no single "governing direction", you can choose either. Imagine a 2x2 grid, there are 4 layout hierarchies which will get the same result.
If you make a mistake and end up with the wrong type of group, you will have a group with only 1 child group of the other type. Then you can just cut that top-level group.
Creating the group hierarchy
After choosing the "governing direction", start advancing in that direction and adding the components in that definitive order. If there is more than 1 component with the same place in the order, it means that you need to add a group in the other direction.
Observe the following schematics for the vertical (red arrow) sequential group:
Starting from top to bottom, there are 3 components in the 1st location of the order (red rectangle). That means that we need a parallel group to section (separate) each component in a sub-hierarchy (green lines). This process continues until we reach the first label, at which point there are no "competing" components, so we just add that component (red rectangle). Same for the second label. This is 1-to-1 the code for the vertical group.
Observe a similar schematics for the horizontal (blue arrow) parallel group:
Starting from top to bottom, there are 3 components in the first location. This means that we need to add a sequential group. However, each of these 3 component shares its sequential location with other components horizontal to it. This means that we need to add 3 parallel groups (blue rectangles) in order to section the components. These 3 parallel groups are added to the sequential group (green rectangle). Then we reach the first label and just add that component (green rectangle). Same for the second label. This is 1-to-1 the code for the horizontal group.
Alignment
I suggest not worrying about alignment at all until you got the group hierarchies the way you wanted. In the cases (such as yours) where you link components, alignment doesn't play a role anyway since the components already fill the whole space (check for yourself). Setting alignments is quick and easy after everything is set.
Non-layout-related notes:
No need to call revalidate and repaint before displaying the frame.
The call setSize(...) is redundant since you later call pack (as you should).
You are calling *setVisible(true)twice: once inmain` and one in the constructor. One of them does simply nothing, just pick one.
Don't call setPrefferedSize(...) on textShowLevel. I'm not even sure what you are passing to it (some ImageObserver thing). You can set its width by specifying the number of columns it contains or by overriding its getPreferredSize().
Don't use the raw type JComboBox, you probably want <String>.
I didn't add the panel to BorderLayout.EAST because it made no sense in my context.
Related
I have an assignment which requires me to create the layout that you see in the image as part of the development of a game. I've never worked with Java for desktop applications before so i'm a complete noob when it comes to using the Swing & AWT libraries. The image suggests that we use a JLayeredPane as our root container and then add the rest on top of it. My issue is that i've tried starting with the background image and the gridLayout but i can't seem to make anything other than the background show up. The grid doesn't show up at all (no border line, no background of the cells) and any other component i've added to it has failed. Can somebody point me in the right direction here? I've read the docs & saw some example of various layouts,containers and components but i can't seem to make all of them work together.
Here's my code so far:
public class BoardView extends JFrame{
// Constructor
public BoardView() {
JFrame window = new JFrame("Sorry Game"); // create a new Jwindow instance
ImageIcon appIcon = new ImageIcon(getClass().getClassLoader().getResource("res/icon.png")); // create the icon for the app
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // when the 'X' button is clicked, the app stops
window.setSize(new Dimension(1000, 700)); // setting the size of the window
window.setResizable(false); // Window won't be resizable
window.setIconImage(appIcon.getImage()); // set the icon for the app
window.setLayout(new BorderLayout());
JLayeredPane layeredPane = new JLayeredPane();
JLabel background = new JLabel();
background.setSize(1000,700);
background.setIcon(new ImageIcon(getClass().getClassLoader().getResource("res/background.png"))); for the JLabel
layeredPane.add(background,0);
JPanel gridPanel = new JPanel(new GridLayout(16,16));
gridPanel.setSize(650,700);
layeredPane.add(gridPanel);
for(int i = 0; i < 256; i++) {
JLabel tile = new JLabel();
tile.setBackground(Color.red);
tile.setBorder(new LineBorder(Color.black));
gridPanel.add(tile);
}
JLabel logo = new JLabel();
logo.setIcon(new ImageIcon(getClass().getClassLoader().getResource("res/sorryImage.png")));
layeredPane.add(logo);
window.add(layeredPane);
window.setLocationRelativeTo(null); // centers the window to the screen
window.setVisible(true); // make the window visible
}
}
My thought process was that i could set the JFrame's layout to a BorderLayout so that i can brake the final layout down into two parts, the West one and the East one. The West one would contain the Grid and the various JLabels and Buttons and the East one would contain the rest of the components. I've tried using the BorderLayout.WEST & EAST parameters when adding components to the JFrame but none has worked or changed a single thing. I've also tried using an index for the depth when adding components to the JLayeredPane as per the docs but again nothing changes.
P.S. Please note that i'm not looking for someone to create the layout for me. I want someone to help me understand what i'm doing wrong and what the best way of creating such layouts is.
In order to initialize the cells of the grid that i want to have images in, don't i need to add them manually in those positions?
If you use a GridLayout every cell must have a component and the components must be added in sequential order. That is as components are added they will wrap automatically to the next row as required.
So even if you don't want an image in a cell you would need to add a dummy component, lets say a JLabel with no text/icon.
An easier approach might be to use a GridBagLayout. The GridBagLayout can be configured to "reserve" space for cells that don't have components. So you can add a component to a specific cell.
import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
public class GridBagLayoutSparse extends JPanel
{
public GridBagLayoutSparse()
{
setBorder( new LineBorder(Color.RED) );
GridBagLayout gbl = new GridBagLayout();
setLayout( gbl );
/*
// Set up a grid with 5 rows and columns.
// The minimimum width of a column is 50 pixels
// and the minimum height of a row is 20 pixels.
int[] columns = new int[5];
Arrays.fill(columns, 50);
gbl.columnWidths = columns;
int[] rows = new int[5];
Arrays.fill(rows, 20);
gbl.rowHeights = rows;
*/
// Add components to the grid at top/left and bottom/right
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
gbc.gridx = 0;
gbc.gridy = 0;
addLabel("Cell 0:0", gbc);
gbc.gridx = 3;
gbc.gridy = 4;
addLabel("Cell 3:4", gbc);
}
private void addLabel(String text, GridBagConstraints gbc)
{
JLabel label = new JLabel(text);
label.setBorder( new LineBorder(Color.BLUE) );
add(label, gbc);
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("GridBagLayoutSparse");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout( new GridBagLayout() );
frame.add(new GridBagLayoutSparse());
frame.setSize(300, 300);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args) throws Exception
{
java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
}
}
Run the code as is and the components will be grouped together in the center.
Uncomment the block comment and run again. The components will be positioned in the appropriate cell.
im trying to make a program to add an admin to a ms access database
I researched many times, figured out all the components need to be in a panel, and only the same type of J stuff can be in a panel, so i made many panels and combined them in a big panel
//frame details
final int FRAME_WIDTH = 1000;
final int FRAME_HEIGHT = 1000;
JFrame aFrame = new JFrame("Add admin");
aFrame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
aFrame.setVisible(true);
aFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//panel declaration
JPanel BigPanel = new JPanel();
JPanel adminnameenter = new JPanel();
JPanel typeadminname = new JPanel();
JPanel adminlastnameenter = new JPanel();
JPanel typeadminlastname = new JPanel();
JPanel buttonaddadmin = new JPanel();
//labels, textfields, and buttons
JLabel newAdminName = new JLabel("Enter admin name");
JTextField adminName = new JTextField(7);
JLabel newadminlastname = new JLabel("Enter admin last name");
JTextField adminlastname = new JTextField(7);
JButton addadmin = new JButton("Add Admin");
//add things to panel
adminnameenter.add(newAdminName);
typeadminname.add(adminName);
adminlastnameenter.add(newadminlastname);
typeadminlastname.add(adminlastname);
buttonaddadmin.add(addadmin);
//add things to big jPanel
BigPanel.add(adminnameenter);
BigPanel.add(typeadminname);
BigPanel.add(adminlastnameenter);
BigPanel.add(typeadminlastname);
BigPanel.add(buttonaddadmin);
//add things to frame
aFrame.add(BigPanel);
the only thing that popped up was a frame that said add admin
Add this code to the end of your function:
aFrame.setVisible(false);
aFrame.setVisible(true);
Or alternatively put
aFrame.setVisible(true);
at the end of your function instead of the beginning.
And all the components will appear. This is because whenever you change anything to your JFrame, it will only change on the user side once it is told to resize or refresh the frame. Also you don't need to put every single component in it's own JPanel, you can simply insert them directly in your BigPanel (small nitpick, but the b in bigPanel, shouldn't be capitalized, seeing as variables start with non-capitalized letters).
Also look into LayoutManagers, they will probably be useful for your application.
https://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html
Here is my shortened version of my code:
JPanel card1 = new JPanel();
JLabel switch1 = new JLabel(new ImageIcon("switch1.jpg"));
switch1.setLocation(TOPSWITCH, LEFTSWITCH1);
JLabel switch2 = new JLabel(new ImageIcon("switch1.jpg"));
switch2.setLocation(TOPSWITCH, LEFTSWITCH2);
JLabel switch3 = new JLabel(new ImageIcon("switch1.jpg"));
switch3.setLocation(TOPSWITCH, LEFTSWITCH3);
card1.add(switch1);
card1.add(switch2);
card1.add(switch3);
card1.setBackground(Color.BLACK);
/* JButton goToRoom = new JButton("TEST");
goToRoom.setLocation(180, 270);
card1.add(goToRoom); */
card1 is added to a JFrame of sized using my_frame.setSize(400, 300);.
The above code works as expected. But when I uncomment the comment piece of code, the JButton appears to the right side of the images(JLabels) instead of appearing below the images. What could be the problem?
Additional information:
final static int TOPSWITCH = 150;
final static int LEFTSWITCH1 = 65 ;
final static int LEFTSWITCH2 = 155;
final static int LEFTSWITCH3 = 245;
switch1.jpg is of dimensions 91 x 150
Note: I want to do this without adding more JPanels.
What could be the problem?
Wanting to set explicit locations.
Fighting the layout manager.
Java GUIs have to work on different OS', screen size, screen resolution etc. using different PLAFs in different locales. As such, they are not conducive to pixel perfect layout. Instead use layout managers, or combinations of them along with layout padding and borders for white space.
First off, I apologize for the long post, I just wanted to be clear and show you my issue so it can better be resolved.
I have the following code:
JPanel panelCard = new JPanel();
String[] cards = {"VISA", "MASTERCARD", "DISCOVER"};
JComboBox cardType = new JComboBox(cards);
panelCard.add(cardType);
GroupLayout layout2 = new GroupLayout(panelCCInfo);
panelCCInfo.setLayout(layout2);
layout2.setAutoCreateGaps(true);
layout2.setAutoCreateContainerGaps(true);
GroupLayout.SequentialGroup hGroup2 = layout2.createSequentialGroup();
hGroup2.addGroup(layout2.createParallelGroup()
.addComponent(cardName)
.addComponent(cardNumber)
.addComponent(expDate));
hGroup2.addGroup(layout2.createParallelGroup()
.addComponent(cardNameField)
.addComponent(cardNumberField)
.addComponent(expDateField));
hGroup2.addGroup(layout2.createParallelGroup()
.addComponent(panelCard));
layout2.setHorizontalGroup(hGroup2);
GroupLayout.SequentialGroup vGroup2 = layout2.createSequentialGroup();
vGroup2.addGroup(layout2.createParallelGroup(Alignment.BASELINE)
.addComponent(cardName)
.addComponent(cardNameField));
vGroup2.addGroup(layout2.createParallelGroup(Alignment.BASELINE)
.addComponent(cardNumber)
.addComponent(cardNumberField));
vGroup2.addGroup(layout2.createParallelGroup(Alignment.BASELINE)
.addComponent(expDate)
.addComponent(expDateField)
.addComponent(panelCard));
layout2.setVerticalGroup(vGroup2);
panelCheckout.add(panelCCInfo, BorderLayout.CENTER);
And when I run it, it displays this window:
But I would like to achieve this:
The problem occurs when I try to add a 3rd vertical group with the panelCard in
the code:
hGroup2.addGroup(layout2.createParallelGroup().addComponent(panelCard));
It would seem that the 2 text field are cut off because of this, but I dont want it cut off.
What can I do to achieve the 2nd picture?
Thanks so much!
Here is how I'd do it:
import javax.swing.*;
import static javax.swing.GroupLayout.*;
import static javax.swing.GroupLayout.Alignment.*;
public class Mastercard {
public static void main(String[] args) {
JLabel lblCardHolder = new JLabel("Card holder");
JTextField tfCardHolder = new JTextField();
JLabel lblCardNumber = new JLabel("Card number");
JTextField tfCardNumber = new JTextField();
JLabel lblExpirationDate = new JLabel("Expiration date");
JTextField tfExpirationDate = new JTextField();
JComboBox combo = new JComboBox(new String[]{"Visa"});
JPanel panel = new JPanel();
GroupLayout layout = new GroupLayout(panel);
panel.setLayout(layout);
layout.setAutoCreateContainerGaps(true);
layout.setAutoCreateGaps(true);
layout.setHorizontalGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup()
.addComponent(lblCardHolder)
.addComponent(lblCardNumber)
.addComponent(lblExpirationDate))
.addGroup(layout.createParallelGroup()
.addComponent(tfCardHolder)
.addComponent(tfCardNumber)
.addGroup(layout.createSequentialGroup()
.addComponent(tfExpirationDate)
.addComponent(combo, DEFAULT_SIZE, 100, PREFERRED_SIZE))));
layout.setVerticalGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(BASELINE)
.addComponent(lblCardHolder)
.addComponent(tfCardHolder))
.addGroup(layout.createParallelGroup(BASELINE)
.addComponent(lblCardNumber)
.addComponent(tfCardNumber))
.addGroup(layout.createParallelGroup(BASELINE)
.addComponent(lblExpirationDate)
.addComponent(tfExpirationDate)
.addComponent(combo)));
JFrame f = new JFrame();
f.setContentPane(panel);
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
This is the result:
GroupLayout is a powerful constraint-based layout manager. When writing a group layout, you basically just describe whether components (or group of components) should be placed in sequence or in parallel. This description is done independently for the horizontal and vertical axis.
Horizontally, there are 2 groups in sequence : the labels, and the rest. The rest is composed of 3 parallel things : 2 textfields, and a sequence of tfExpirationDate and combo. This is, in plain english, what the layout.setHorizontalGroup(... describes.
Vertically, there are 3 groups in sequence : one composed of a label and a textfield in parallel, another composed of a label and a textfield in parallel, and yet another composed of a label, a textfield and a combobox in parallel. This is what layout.setVerticalGroup(... describes.
The nesting of these groups and components is important, this is why I indented everything correctly.
I find this approach of describing constraints quite easy to reason about, using only 2 concepts : sequential groups and parallel groups. Compared to grid-based layouts, it has the advantage that you don't break everything each time you want to add or move a component.
Ok I figured it out using a complex combination of GridBagLayout and BorderLayout
what a mess.... :)
I have a code:
Box box_general = Box.createHorizontalBox();
Box box_panel1 = Box.createVerticalBox();
Box box_panel2 = Box.createVerticalBox();
JPanel jpanel_1 = new JPanel();
jpanel_1.setPreferredSize(new Dimension(50, 152));
jpanel_1.setOpaque(true);
jpanel_1.setBorder(BorderFactory.createLineBorder(Color.BLUE));
JPanel jpanel_2 = new JPanel();
jpanel_2.setPreferredSize(new Dimension(340, 152));
jpanel_2.setOpaque(true);
jpanel_2.setBorder(BorderFactory.createLineBorder(Color.RED));
JTextField jtxtf_populationSize = new JTextField();
jtxtf_populationSize.setSize(10, 20);
JTextField jtxtf_processorsAmount = new JTextField();
JButton jbtn_loadProcesses = new JButton("File path");
box_panel1.add(Box.createRigidArea(new Dimension(0,4)));
box_panel1.add(jtxtf_processorsAmount);
box_panel1.add(Box.createRigidArea(new Dimension(0,20)));
box_panel1.add(jbtn_loadProcesses);
jpanel_1.add(box_panel1);
JLabel jlbl_populationSize = new JLabel("Enter the population size");
JLabel jlbl_processorsAmount = new JLabel("Enter the amount of processors");
JLabel jlbl_loadProcesses = new JLabel("Load processes from file");
jlbl_populationSize.setFont(font);
jlbl_processorsAmount.setFont(font);
jlbl_loadProcesses.setFont(font);
box_panel2.add(jlbl_populationSize);
box_panel2.add(Box.createRigidArea(new Dimension(0,4)));
box_panel2.add(jlbl_processorsAmount);
box_panel2.add(Box.createRigidArea(new Dimension(0,15)));
box_panel2.add(jlbl_loadProcesses);
jpanel_2.add(box_panel2);
box_general.add(jpanel_2);
box_general.add(Box.createRigidArea(new Dimension(10,0)));
box_general.add(jpanel_1);
It creates 3 boxes, where the general box contains two other boxes. The problem is: in the box all the compopents are stretched of width. For example, there is a line jtxtf_populationSize.setSize(10, 20); but this text field is stretched in the box_panel1 on width. I tried to use a BoxLayout with it's Alignment_X but this didn't work.
Could you, please, advise me, what to do - how to avoid stretching?
Most of the swing layouts will use the preferred size and the minimum/maximum size over a call to setSize. The key here is to get the right preferred and minimums so that they don't shrink too much, and then insert a strut (Box#createHorizontalStrut) to fill up space where you don't want a component.
With complex layouts like this, consider the SpringLayout, which admittedly has a higher learning curve, but once you get used to it, will allow you to more naturally state the constraints you want.