Use BorderLayout to create two even columns - java

I'm trying to create a program using BorderLayout() that I want to look like this (but with even left right height and such)
although I am having trouble resizing the two JPanels (two boxes within the large box). At the moment my GUI looks like this,
I believe it is due to the CENTER still being there, I looked up on how to remove it but could not get it to work,
Question
Can can I edit this so that it will look like the top image.
package fuelstation;
import java.awt.*;
import java.util.*;
import javax.swing.*;
public class Fuelstation extends JFrame {
JButton btn1 = new JButton("Random Button");
public Fuelstation() {
JFrame frame = new JFrame("Fuel Station");
frame.setLayout(new BorderLayout());
frame.setResizable(false);
frame.setPreferredSize(new Dimension(500,350));
frame.setMaximumSize(new Dimension(500,350));
// Left Hand Side
JPanel lhs = new JPanel();
JTextArea tf_list = new JTextArea();
tf_list.setEditable(false);
tf_list.setWrapStyleWord(true);
tf_list.setText("This is a list of items");
lhs.add(tf_list);
tf_list.setSize(245, 325);
lhs.setBorder(BorderFactory.createTitledBorder("Left"));
// Left Hand Side End
// Right Hand Side
JPanel rhs = new JPanel();
rhs.setAlignmentX(Component.CENTER_ALIGNMENT);
rhs.setBorder(BorderFactory.createTitledBorder("Right"));
rhs.add(btn1);
tf_list.setSize(245, 325);
JPanel center = new JPanel();
center.setSize(0, 0);
// Right Hand Side End
frame.add(lhs, BorderLayout.WEST);
frame.add(center, BorderLayout.CENTER);
frame.add(rhs, BorderLayout.EAST);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
Fuelstation gui = new Fuelstation();
}
}

You need to drop the requirement to use a BorderLayout. The resizing policy for components when using a BorderLayout is stated in the class javadoc
The components are laid out according to their preferred sizes and the constraints of the container's size. The NORTH and SOUTH components may be stretched horizontally; the EAST and WEST components may be stretched vertically; the CENTER component may stretch both horizontally and vertically to fill any space left over.
By forcing your JFrame to a certain size
frame.setResizable(false);
frame.setPreferredSize(new Dimension(500,350));
frame.setMaximumSize(new Dimension(500,350));
your center component will take the extra width, as the EAST and WEST component will only stretch vertically.
So you need to use another LayoutManager. You can use the Visual guide to layout managers to get a grasp of the available LayoutManagers and their capabilities. That document states that a GridLayout would be a good candidate:
GridLayout simply makes a bunch of components equal in size and displays them in the requested number of rows and columns

Related

Why do buttons go off screen on Flow Layout?

I'm learning flow layout from Head First Java and I'm trying to have buttons wrap around as it says a Flow Layout should (left to right, top to bottom).
import javax.swing.*;
import java.awt.*;
public class Flow {
public static void main(String[] args) {
Flow gui = new Flow();
gui.go();
}
public void go() {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
JButton buttonOne = new JButton("hello");
JButton buttonTwo = new JButton("this is");
JButton buttowThree = new JButton("woody");
panel.add(buttonOne);
panel.add(buttonTwo);
panel.add(buttonThree);
frame.getContentPane().add(BorderLayout.EAST, panel);
frame.setSize(200,200);
frame.setVisible(true);
}
}
However, when setting the panel on the EAST region of the frame, the buttons go off the screen and don't wrap around. If I set the panel on the NORTH or SOUTH region, I only see two buttons. If I set the panel on the CENTER region, they DO wrap and can see all of them clearly. Why is this?
If you're adding a component to a BorderLayout frame, the East and West regions will let the component get its preferred width. Since the panel contains three buttons and places them side by side, the preferred width of the panel is that of the three buttons side by side. Therefore, it is going "off-the-screen" since that is the preferred width. If you were to a button on to the frame on the EAST region instead and fill it up with enough text, the same would happen. The CENTER region gets whatever is left that the other regions haven't taken up already. Since that is the policy of the CENTER region, the panel does NOT get its preferred width or height, therefore forcing the components of the panel to wrap.
As far as the NORTH and SOUTH regions go, the panel will get its preferred height which is the height of the tallest component (in the example all buttons are the same height). Therefore it sees no reason to wrap. The panel however, DOESN'T get its preferred width. Therefore the buttons are "cut off" since the max width the panel can have is that of the frame. You will notice as the frame resizes, the buttons appear on the screen as space is made available on the panel.

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();
}
}

JLabel wont change Width

I'm programming right now a Chomp Game for Uni. Everything works fine but the Label at the bottom. Its background is supposed to fill out the entire bottom. In the attachment you can see how it instead looks now. I tried setting the minimum and the preferred size of the label. The Height is changing but the width just stays adjusted to the text. How can I change that?
Note: The snippet only contains the setting up of the Frame and Panels in a custom method and not the main class.
private void init()
{
JFrame fenster = new JFrame();
this.spielfeld = new SpielfeldPanel(M, N);
this.anzeige = new SpielerAnzeigeLabel(this.spieler);
JPanel panel = new JPanel();
BoxLayout boxlayout = new BoxLayout(panel,BoxLayout.Y_AXIS);
panel.setLayout(boxlayout);
fenster.setTitle("Chomp");
fenster.setSize(1000,700);
panel.setPreferredSize(new Dimension(1000, 60));
Dimension d = new Dimension(getPreferredSize());
panel.setMinimumSize(d);
panel.add(spielfeld);
panel.add(anzeige);
fenster.add(panel);
this.spielfeld.setVisible(true);
this.anzeige.setVisible(true);
panel.setVisible(true);
fenster.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
A BoxLayout respects the width of the component to the label is displayed at its preferred width/height.
A JFrame uses a BorderLayout by default. So just add the label to the frame independently of the panel:
//panel.add(anzeige);
//fenster.add(panel);
fenster.add(panel, BorderLayout.CENTER);
fenster.add(anzeige, BorderLayout.PAGE_END);
The PAGE_END constraint respects the height but makes the width equal to the space available. Read the section from the Swing tutorial on How to Use BorderLayout for more information and examples.

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).

Setting the size of panels

I have 3 panels. One is the main panel which holds 2 smaller panels.
For the main panel, I used
setPreferredSize(new Dimension(350, 190));
For the smaller left panel, I used
setPreferredSize(new Dimension(100, 190));
For the smaller right panel, I used
setPreferredSize(new Dimension(250, 190));
but the smaller panels remain the same size. How can I fix this?
This is the code I have in my main Panel.
import model.*;
import java.awt.*;
import javax.swing.*;
public class Panel extends JPanel
{
public Panel(Prison prison)
{
setup();
build(prison);
}
private void setup()
{
setBorder(BorderFactory.createLineBorder(Color.blue));
setLayout(new BorderLayout(1, 1));
setPreferredSize(new Dimension(350, 190));
}
private void build(Prison prison)
{
JTabbedPane tab = new JTabbedPane();
tab.addTab("Input", null, new InputPanel(), "Input");
tab.addTab("Display", null, new DisplayPanel(), "Display");
add(tab);
}
}
Don't do this.
The whole point of layout managers is to allow dynamic resizing, which is necessary not just for user-resizable windows but also changing texts (internationalization) and different default font sizes and fonts.
If you just use the layout managers correctly, they will take care of panel sizes. To avoid having your components stretched out all over the screen when the user increases the window size, have an outermost panel with a left-aligned FlowLayout and the rest of the UI as its single child - that will give the UI its preferred size and any surplus is filled with the background color.
It looks like you're using a GridLayout, or perhaps a FlowLayout, neither being what you want. You probably want to use a BoxLayout, which respects its components preferred sizes.
final JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
p.add(leftPanel);
p.add(mainPanel);
p.add(rightPanel);
also- that is the preferred size. if you don't want to allow resizing, you can also set the maximum sizes as well.
if you're able, you may want to check out the MIG layout, but BoxLayout is also easy to use and in the java toolkit already.
It's this one.
buttonPanel = new JPanel();
buttonPanel.setSize(new Dimension(30, 100));
Don't let the layout manager adjust your sizes.

Categories

Resources