Using WrapLayout with multiple adjacent JPanels is causing Panel sizing issues - java

I have 3 adjacent JPanels that each use WrapLayout to display a variable number of 1x16 grids.
It works great for the panel which contains the most 1x16 grids, however, the other two panels' dimensions seem to be determined by the panel that contains the most 1x16 grids. If, for example, panels 1 and 2 have only one 1x16 grid respectively, but panel 3 has ten 1x16 grids spread across two rows, then panel 1 and 2 both have a 1x16 grid-sized empty space beneath their respective 1x16 grids.
I basically want to get each panel's resizing to operate independently of the other panels. I've looked through camickr's src code for WrapLayout and can't quite work out what I should change to get the desired result.
In terms of code, it's tricky to know how to include a succinct and instructive section, as the code is quite spread out and I'm not sure what part is causing this issue. I'm just setting the panels' layout as a left-justified WrapLayout.
I've included an image below which might provide some context. The image shows part of two of the three JPanels (coloured cyan) and the accompanying title JLabel for one of those JPanels (coloured green). The 1x16 grids on each panel are managed using camickr's WrapLayout. All three cyan JPanels are contained within a larger display JPanel that has then been packed into a JScrollPane (hence the grey scroller to the right of the image).
Any help would be really appreciated.
Here's another image I created that shows the issue a little more clearly. The third panel in the image wraps to a new row to display all the 1x16 grids that it contains, and in so doing, doubles the height of the other two panels, despite them not needing to resize.
Here's how I want the GUI to display:

Judging from the desired behaviour vs the actual behaviour images, the problem lies in the LayoutManager you use to lay out the 3 panels into their parent panel/frame (which I am guessing is a GridLayout because the 3 panels have equally distributed sizes). If so, use some other LayoutManager, such as a vertical BoxLayout.
An example code and tutorial can be found in the Oracle's corresponding one (the actual code sample of which, can be found in this link with fancy code coloring, or here as plain text).

I created the following GUI.
I created a JFrame. I created one main JPanel to place inside the JFrame. The main JPanel uses a GridBaglayout to separate three cyan JPanels.
Each cyan JPanel calculates a preferred size based on the number of black JPanels placed in the cyan JPanel. Change the boxesPerRow value to get a different number of boxes per row.
Each black JPanel is created with a preferred size of 20 x 80 pixels;
Here's the complete runnable code. A minimal reproducible example, in other words.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class BoxesGUI implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new BoxesGUI());
}
#Override
public void run() {
JFrame frame = new JFrame("Boxes");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createMainPanel() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setBackground(Color.BLACK);
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.LINE_START;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(5, 5, 5, 5);
gbc.weightx = 1.0;
gbc.gridx = 0;
gbc.gridy = 0;
panel.add(createCyanPanel(1), gbc);
gbc.gridy++;
panel.add(createCyanPanel(1), gbc);
gbc.gridy++;
panel.add(createCyanPanel(20), gbc);
return panel;
}
private JPanel createCyanPanel(int count) {
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEADING, 5, 5));
panel.setBackground(Color.CYAN);
JPanel dummyPanel = createBlackPanel();
Dimension d = dummyPanel.getPreferredSize();
int boxesPerRow = 8;
int width = (d.width + 5) * boxesPerRow + 5;
int height = ((count + boxesPerRow - 1) / boxesPerRow) * (d.height + 5) + 5;
panel.setPreferredSize(new Dimension(width, height));
for (int i = 0; i < count; i++) {
panel.add(createBlackPanel());
}
return panel;
}
private JPanel createBlackPanel() {
JPanel panel = new JPanel();
panel.setBackground(Color.BLACK);
panel.setPreferredSize(new Dimension(20, 80));
return panel;
}
}

Related

How to make components evenly share JPanel container vertical area with GridBagLayout layout on resizing?

The problem:
JPanel with GridBagLayout contains two JScrollPane components, the top one contains JTextArea, the bottom one contains JTable. I expect this set up to make the components fluidly fill the container JPanel and evenly share the vertical area of it on resizing. What actually happens is that the top JScrollPane component shrinks vertically on resizing giving more vertical area to the bottom JScrollPane component to invade; this happens at some sizes, I don not know if they are random.
Important notes:
I already applied GridBagConstraints#weighty = 0.5; to both components, which is supposed to do the job.
I noticed that the problem is because of the presence of the JTextArea, in that if I switch locations; make the JScrollPane/JTextArea on the bottom side and JScrollPane/JTable on the top side; the bottom component JScrollPane/JTextArea shrinks vertically giving more vertical area to the top component JScrollPane/JTable to invade.
I know this exact case can be solved simply using GridLayout(2,1) instead of GridBagLayout (or may be other solutions), however I am fan of GridBagLayout and I want to use most of it. Also if I want to add three components instead of two and I want to make them share the vertical area by percentage for example (%25, %25, 50%) I can use GridBagConstraints#weighty = (0.25, 0.25, 0.5) which is easily applicable with GridBagLayout.
So, in this case how to make components evenly share the vertical area of JPanel container with GridBagLayout on resizing?. Or, in other words; how to enforce components to respect GridBagConstraints#weighty = 0.5; setting on resizing which is applied to both?
Code in SSCCE format:
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.table.DefaultTableModel;
public class GridBagFluidFill {
private static JPanel createFormPanel() {
JPanel containerPanel = new JPanel(new GridBagLayout());
containerPanel.setPreferredSize(new Dimension(350, 200));
JScrollPane scrollableTextArea;
JScrollPane scrollableTable;
JTextArea textArea = new JTextArea();
scrollableTextArea = new JScrollPane(textArea);
DefaultTableModel model = new DefaultTableModel(new String[]{"Column1", "Column2", "Column3"}, 0);
JTable table = new JTable(model);
scrollableTable = new JScrollPane(table);
GridBagConstraints c = new GridBagConstraints();
c.gridy = 0;
c.weightx = 1.0;
// I expect this to reserve 50% of the height all time.
c.weighty = 0.5;
c.fill = GridBagConstraints.BOTH;
c.anchor = GridBagConstraints.PAGE_START;
containerPanel.add(scrollableTextArea, c);
c = new GridBagConstraints();
c.gridy = 1;
c.weightx = 1.0;
// I expect this to reserve 50% of the height all time.
c.weighty = 0.5;
c.fill = GridBagConstraints.BOTH;
c.anchor = GridBagConstraints.PAGE_END;
containerPanel.add(scrollableTable, c);
return containerPanel;
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(() -> {
JPanel formPanel = createFormPanel();
JFrame frame = new JFrame("GridBagFluidFill");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(formPanel);
frame.pack();
frame.setVisible(true);
});
}
}
GridBagLayout is complex, and while its documentation does describe all of its functionality, some of it is easy to misinterpret.
I already applied GridBagConstraints#weighty = 0.5; to both components, which is supposed to do the job.
That is not what weightx and weighty do.
Equal weightx and weighty values do not coerce components into having the same width or height. The weight values determine the distribution of extra space when a container is larger than the preferred sizes of each component.
Here is a program which demonstrates this:
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JPanel;
import javax.swing.JFrame;
public class GridBagEqualWeightsDemo {
static void showWindow() {
// Source: https://www.gutenberg.org/files/98/98-h/98-h.htm
String text =
"It was the best of times, it was the worst of times, it was"
+ " the age of wisdom, it was the age of foolishness, it was the"
+ " epoch of belief, it was the epoch of incredulity, it was the"
+ " season of Light, it was the season of Darkness, it was the"
+ " spring of hope, it was the winter of despair, we had everything"
+ " before us, we had nothing before us, we were all going direct"
+ " to Heaven, we were all going direct the other way—in short,"
+ " the period was so far like the present period, that some of its"
+ " noisiest authorities insisted on its being received, for good"
+ " or for evil, in the superlative degree of comparison only.";
JTextArea topArea = new JTextArea(text, 4, 20);
topArea.setLineWrap(true);
topArea.setWrapStyleWord(true);
JTextArea bottomArea = new JTextArea(text, 8, 20);
bottomArea.setLineWrap(true);
bottomArea.setWrapStyleWord(true);
JScrollPane top = new JScrollPane(topArea);
JScrollPane bottom = new JScrollPane(bottomArea);
top.setMinimumSize(top.getPreferredSize());
bottom.setMinimumSize(bottom.getPreferredSize());
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.weightx = 1;
gbc.weighty = 0.5;
panel.add(top, gbc);
panel.add(bottom, gbc);
JFrame frame = new JFrame("GridBagConstraints Equal Weights");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> showWindow());
}
}
As you can see, the two components start out with different preferred heights, so GridBagLayout will never give them the same height. As you make the window taller, the components’ respective heights look more similar due to the smaller relative difference, but they are never the same.
GridBagLayout only uses the weighty to determine how to distribute the extra space—that is, the container height which exceeds each component’s (different) preferred height. If the panel is 50 pixels higher than the preferred height, as computed based on each child component’s preferred size, then equal weighty values means each component will be laid out with 25 pixels added to its respective preferred height.
If you want to force two components which may have different preferred sizes to always have the same width and/or height, GridBagLayout is the wrong tool for the job. As you have mentioned, GridLayout is well suited to this. SpringLayout can also do this, though its usage is complex.
You are free (and encouraged!) to use multiple panels inside each other with different layouts.
I already applied GridBagConstraints#weighty = 0.5; to both components, which is supposed to do the job.
The weighty constraint is used to tell the GridBagLayout how to allocate "extra" (and apparently less) space.
That is, each component is first allocated its preferred space. Then if there is extra (or apparently less) space available, that constraint is used.
If you add debug code to display the preferred sizes of each scroll pane you will get:
java.awt.Dimension[width=223,height=19] // text area
java.awt.Dimension[width=453,height=403] // table
So the issue is with this statement:
containerPanel.setPreferredSize(new Dimension(350, 200));
You are forcing the components to be smaller than their preferred size. So it appears the GridBagLayout is allocating 50% to each.
I was wondering why JTextArea shrinks without a good reason
As the height of the frame grows each component is allocated 50% until the point at which the frame is large enough to display each component at its preferred size. This is why the text area shrinks and the table jumps.
As you increase the height from there extra space is allocated at 50/50 as expected.
If you uncomment the setPreferredSize() statement you will see the natural layout and the reason for the jumping becomes clear.
I want to make them share the vertical area by percentage for example (%25, %25, 50%)
If you want allocations like that then check out Relative Layout which was designed for this purpose.

How to create a fluid 2-column GridLayout within a ScrollPane?

I have done tons of searching over the past two hours, and I've given up. The image below shows what I am trying to achieve (don't judge my drawing it's late and I made it in paint quickly):
Basically, I want a JScrollPane to have a JPanel with a 2-column GridLayout, and as I add elements I want the GridLayout to expand downward. I want the elements to use their Preferred Size and to NOT expand within the GridLayout.
Currently I have a JScrollPane and a JPanel with a GridLayout, and a JPanel containing the grid with a FlowLayout. As a test, I add 10 buttons to the grid. Here's my current code:
// Setup main panel
JPanel pnlUsers = new JPanel(new GridLayout(0, 2));
pnlUsers.setOpaque(true);
pnlUsers.setBackground(Color.GREEN);
// Setup GridLayout Container
JPanel pnl2 = new JPanel();
pnl2.setOpaque(false);
pnl2.add(pnlusers);
// Setup scrollpane
JScrollPane scrUsers = new JScrollPane(pnl2);
scrUsers.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
scrUsers.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrUsers.setOpaque(false);
scrUsers.getViewport().setOpaque(false);
scrUsers.setBorder(null);
// Add users
for (int i = 0; i < 10; i++) {
pnlUsers.add(new JButton("Button " + (i + 1));
}
This gives a very good result, with the buttons using their preferred size as seen in the image below:
Unfortunately, the buttons are still not filling the horizontal space. So, I attempted to make pnl2 a BoxLayout instead and add some vertical glue...
// Setup GridLayout Container
JPanel pnl2 = new JPanel();
pnl2.setLayout(new BoxLayout(pnl2, BoxLayout.Y_AXIS));
pnl2.setOpaque(false);
pnl2.add(pnlusers);
pnl2.add(Box.createVerticalGlue());
I also created my own temporary button class that sets the preferred size to use the minimum size:
public class TempButton extends JButton {
public PLTempButton(String msg) {
super(msg);
this.setPreferredSize(this.getMinimumSize());
}
}
Which resulted in the following:
This is much better, but there's still a problem. If there are not enough buttons to cause the JScrollPane to scroll, the buttons height are not consistent and will resize as you resize the window vertically. Why?
Obviously when I add 100 buttons, they use their preferred size:
Maybe I'm just not understanding the differences between minimum, preferred and maximum size? But I want the buttons to use the height they're set even if there aren't enough to cause the scroll-pane to, well, scroll. What can I do to fix this?
1) How do I even get a GridLayout within a ScrollPane?
Create a JPanel
Apply a GridLayout to the JPanel
Wrap the JPanel in a JScrollPane
For example
JPanel panel = new JPanel(new GridLayout(0, 2));
JScrollPane scrollPane = new JScrollPane(panel);
// Add the scroll pane to what ever parent container you're using
2) How do I get said GridLayout to expand horizontally, including the added components?
That doesn't make sense with regards to all previous part of the question, you said "and have it slowly expand downward the more things I add"
Having said that, the "basic" answer is, you configure the GridLayout and let it do it's job. The above example is configured for 2 columns and n number of roes
3) How would I add a "margin" to the components?
That's a broad answer, you could:
Make use of the horizontal and vertical gap properties of the GridLayout
Use a compound layout and adjust the insets of the an appropriate layout manager (like GridBagLayout)
Recommendations
I would recommend reading through Laying Out Components Within a Container to get a better understanding of the layout managers.
Remember, you not stuck to using one.
I would also recommend reading through How to Use Scroll Panes as you're asking basic questions about the API which are better covered through the tutorials
The following mre demonstrates creating a JPanel with GridLayout warped by JScrollPane and setting its horizontal and vertival gaps.
The Jpanel is added using a BorderLayout (the default layout manager of JFrame content pane) which allows it to expand:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class SwingMain {
private String text ="Growing ";
private JPanel grid;
private JFrame f;
SwingMain() {
creategui();
}
void creategui(){
f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationRelativeTo(null);
JButton addComponentBtn = new JButton("Add Component");
addComponentBtn.addActionListener(e-> addComponent());
f.add(addComponentBtn, BorderLayout.PAGE_START);
grid = new JPanel(new GridLayout(0, 2, 10, 10)); //any number of rows, 2 columns, H and V gap
f.add(new JScrollPane(grid), BorderLayout.CENTER);
f.pack();
f.setVisible(true);
}
void addComponent() {
grid.add(new JLabel(text) );
text +="."; //make text longer so JLable grows
f.pack();
}
public static void main(String[] args) {
new SwingMain();
}
}

How to fill Cells of GridbagLayout with the controls in Swing?

I need to design a swing GUI which has a JFrame with a Menu on top and another main panel having three more panels in center and a separate panel in the bottom of the panel. The required design of the UI is as below
But when I run my swing application I get the output like this (all the panels are packed in the center of the window)
Below is my code
import java.awt.*;
import javax.swing.*;
public class FrontEndView {
private JFrame mainFrame;
private JPanel mainPanel,subPanelUp,subPanelDown,panelLeft,panelRight,panelCenter,panelDown;
private JScrollPane scrollPane;
private JList logViewList;
private JPanel panel1;
public FrontEndView(){
this.prepareGUI();
}
public void prepareGUI(){
mainFrame=new JFrame("GUI");
Toolkit tk = Toolkit.getDefaultToolkit();
int xSize = ((int) tk.getScreenSize().getWidth());
int ySize = ((int) tk.getScreenSize().getHeight());
mainFrame.setSize(xSize,ySize);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setResizable(true);
mainFrame.setLayout(new BorderLayout());
mainPanel=new JPanel();
mainPanel.setLayout(new GridBagLayout());
mainPanel.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
GridBagConstraints gridbagConstMain = new GridBagConstraints();
GridBagConstraints gridbagConstSub = new GridBagConstraints();
subPanelUp=new JPanel();
subPanelUp.setLayout(new GridBagLayout());
subPanelUp.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
panelLeft=new JPanel();
panelLeft.setBorder(BorderFactory.createTitledBorder("Message Defs"));
gridbagConstSub.fill = GridBagConstraints.HORIZONTAL;
gridbagConstSub.weightx = 0.5;
gridbagConstSub.gridx = 0;
gridbagConstSub.gridy = 0;
subPanelUp.add(panelLeft, gridbagConstSub);
panelCenter=new JPanel();
panelCenter.setBorder(BorderFactory.createTitledBorder("Main Workspace"));
gridbagConstSub.fill = GridBagConstraints.HORIZONTAL;
gridbagConstSub.weightx = 0.5;
gridbagConstSub.gridx = 1;
gridbagConstSub.gridy = 0;
subPanelUp.add(panelCenter, gridbagConstSub);
panelRight=new JPanel();
panelRight.setBorder(BorderFactory.createTitledBorder("Script Viewer"));
gridbagConstSub.fill = GridBagConstraints.HORIZONTAL;
gridbagConstSub.weightx = 0.5;
gridbagConstSub.gridx = 2;
gridbagConstSub.gridy = 0;
subPanelUp.add(panelRight, gridbagConstSub);
mainPanel.add(subPanelUp,gridbagConstMain);
subPanelDown=new JPanel();
subPanelDown.setLayout(new BorderLayout());
panelDown=new JPanel();
panelDown.setBorder(BorderFactory.createTitledBorder("Log View"));
logViewList= new JList();
panelDown.add(logViewList);
gridbagConstSub.fill = GridBagConstraints.HORIZONTAL;
//gridbagConst.ipady=20;
//gridbagConst.weightx = 0.0;
gridbagConstSub.gridwidth = 5;
gridbagConstSub.gridx = 0;
gridbagConstSub.gridy = 0;
subPanelDown.add(panelDown,BorderLayout.PAGE_END);
mainPanel.add(subPanelDown, gridbagConstSub);
scrollPane=new JScrollPane(mainPanel,ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
mainFrame.add(scrollPane);
mainFrame.setVisible(true);
}
public static void main(String[] args){
FrontEndView frontEnd = new FrontEndView();
}
}
I want to fill the GridBagLayout's cells with the relevant panel/control it holds as shown in the design and also each panel should have its controls filled inside (I need to add a JList inside the panelDown whose size should be the size of the panelDown JPanel).Simply I don't need any extra space visible in my JFrame. Please guide me on what is missing in my code.
I would suggest you can use nested panels with different layout managers to solve the problem.
The default layout of a frame is a BorderLayout.
So you could create a panel and add it to the PAGE_END so it displays the entire width at the bottom.
Then you can create another panel that uses a GridLayout. You can then add 3 child panels to this panel and each panel can use its own layout. Then you add this panel to the CENTER of the frame. As the frame size changes the extra spaces will be allocated to the CENTER so the panels will dynamically grow.
Edit:
Too many panels for me to take the time to understand what is happening
I was suggesting a structure like this:
frame (which by default uses a BorderLayout)
--- CENTER
panel using GrigBagLayout
childPanel1
childPanel2
childPanel3
---- PAGE_END
JScrollPane containing the JList
When you create the JList the basic code would be:
JList list = new JList(...);
list.setVisibleRowCount(5);
JScrollPane scrollPane = new JScrollPane( list );
There is no need to create a panel just to add the list to another panel. The point of setting the visible row count is to give the JList a fixed height. Scrollbars will then appear in the scroll pane as needed.
Now that the PAGE_END has a fixed height component all the reset of the space will go to the component that you add to the CENTER of the frame.
all the panels are packed in the center of the window)
The panels are displayed at their preferred sizes when you use the GridBagLayout. If the total size of all the panels is less than the size of the scrollpane then they will be in the center. If you want the panels to fill the space available, then I believe you need to use the weightx/y constraints. Read the section from the Swing tutorial on How to Use GridBagLayout which describes all the constraints.
That is why I suggested a GridLayout instead. It will make all the panels the same size and will fill the viewport of the scroll pane without playing with constraints.
mainFrame.add(menubar,BorderLayout.NORTH);
That is not how you add a menubar to the frame.
You should be using:
mainFrame.setJMenuBar(menuBar);
You were told this in your last question. Why did you not listen to the advice??? Why should we take the time to help when you don't pay attention to what is suggested.
Based on your instructions I changed my design in a way all of the outer panels are used with Border Layout and the inner most ones with more controls were used with Grid, GridBag and FlowLayouts based on the requirement. In that way the entire design could be done nicely.
Also if a particular panel within a cell of a layout needs to be expanded, I used the setPreferredSize(new Dimension(int,int)) whenever required.

Controlling textbox height in a Java Swing layout

I have a form, and when it renders using pack, the textboxes have a nice default height. But when I resize it - or in this case, if I override getPreferredSize to make it larger on startup - the textboxes resize proportionally.
I keep going in circles trying to understand the layout manager classes... the related questions that are coming up seem like they're really close, but I'm just not following them!
In the class below, if I comment out the getPreferredSize overload, the textboxes are sized by the system to be "just right". Add getPreferredSize back, or resize manually, and the textbox proportions expand/contract with the form. There's got to be something simple I'm missing!
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.TitledBorder;
public class TestTextBox extends JFrame {
private JTextField jtfRate = new JTextField();//jtfAnnualInterestRate
private JButton jbtComputeLoan = new JButton("Compute Sentence");
// Constructor buids the panel
public TestTextBox() {
// a panel with the fields
JPanel p1 = new JPanel(new GridLayout(5, 2));
p1.add(new JLabel("Annual Interest Rate"));
p1.add(jtfRate);
p1.setBorder(new TitledBorder("This is a border with enough text that I want to see it"));
// a panel with the button
JPanel p2 = new JPanel(new FlowLayout(FlowLayout.CENTER));
p2.add(jbtComputeLoan);
// Put the panels on the frame
add(p1, BorderLayout.CENTER);
add(p2, BorderLayout.SOUTH);
}
#Override
public Dimension getPreferredSize() {
// This will help Pack to pack it up better
return new Dimension(600, 300);
}
public static void main(String[] args) {
TestTextBox jailCell = new TestTextBox();
jailCell.pack(); // Arrange controls compactly based on their properties
jailCell.setTitle("Calculate your Sentence");
jailCell.setLocationRelativeTo(null); // sure, center it, whatever
jailCell.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jailCell.setVisible(true);
}
}
Obviously, this is a case for a GUI layout tool. But this isn't production code, this is a Java class in which I'm trying my best to learn why it works - that way I'll know what the GUI tools are doing.
Update: Thanks to the answer I got, I was able to figure out the basics of the GridBag. It seems pretty closely related to HTML <table>s. It took much longer than it should have, mostly because I kept forgetting , c); to apply the GridBagConstraints to the control! Here's a sample of what the relatively simple add above turned into:
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 0;
p1.add(new JLabel("Annual Interest Rate"), c);
c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 1;
c.gridy = 0;
c.weightx = 0.25;
p1.add(jtfRate, c);
The default behaviour of GridLayout is to provide each component with equal amounts of available space. This means, as you make the component larger, they will get bigger, as you make it smaller, the will get smaller.
You could use a GridBagLayout instead, which will allow you to layout your components in a grid pattern but control how much of the cell they should occupy...
Take a look at How to use GridBagLayout for more details...

Question about making a JAVA GUI of a certain format

I am trying to make a GUI that looks something like this:
I only know how to use the BorderLayout which has space for 5 buttons. North, West, Center, East, and South.
Since I need to have 6 components on the top line, this approach can't work. I'm not sure how to make it so that I can have more than 1 component on the top line. Are there other layouts that I can use or is there some way I can manipulate BorderLayout so that I can put 6 components on the top line?
What you need to do is nest components inside of other components. For example, the top (North) should be one JPanel. That JPanel will contain the 6 components on the top.
The code may look similar to the following:
JPanel northPane = new JPanel();
northPane.add(new JLabel("Principle: "));
northPane.add(principleTextBox);
... and so on
mainPanel.setLayout(new BorderLayout());
mainPanel.add(northPanel, BorderLayout.NORTH);
The Center component will probably be another JPanel containing the two center buttons. And the South component will be another JPanel containing the single JLabel or simply the JLabel.
If you don't have to use a BorderLayout for the main panel, it may be easier to use a BoxLayout.
Once again I turn to miglayout, the absolute best layout manager for Java. No nested JPanels, just a simple layout using string based constraints.
With debug mode on:
After resizing the window (note the ratio of the size of the textfields remains the same)
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import net.miginfocom.swing.MigLayout;
/**
*
* #author nicholasdunn
*/
public class InterestCalculator extends JPanel {
public InterestCalculator() {
super(new MigLayout("debug, fill", "align center"));
// Make 6 components cram into one cell
add(new JLabel("Principal:"), "split 6");
// This textfield grows at twice the normal rate
add(new JTextField(), "growx 200");
add(new JLabel("Interest rate (percentage):"));
// This one at a normal rate
add(new JTextField(), "growx 100");
add(new JLabel("Years:"));
// This one at half the normal rate
add(new JTextField(), "growx 50, wrap");
// The row with the two buttons
add(new JButton("Compute simple interest"), "split 2");
add(new JButton("Compute compound interest"), "wrap");
// The result label
add(new JLabel("The result with simple interest would be"));
}
public static void main(String[] args) {
JFrame frame = new JFrame("");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new InterestCalculator();
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
}
If I were recreating that UI, I would start with a JPanel using a GridLayout with 3 rows and 1 column. In each column I would add a child JPanel.
Then for each row I would use a GridBagLayout to position the components.
Here is a tutorial about layout managers.
Remember that you can always add several elements to a JPanel and apply a specific layout to that JPanel. Then you can nest panels(add panels inside other panels).

Categories

Resources