Java, setting layout to null - java

I have been using a null layout and I alot of people will say it shouldn't be done this way. Is there a better way?
Some code as example:
import javax.swing.*;
public class Main{
public static void main(String args[]){
JFrame frame = new JFrame();
JPanel panel = new JPanel();
JButton button = new JButton("Click");
//JFrame, frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setSize(500, 500);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
//JPanel, panel
panel.setLayout(null); //<<---- Is this correct?
frame.add(panel);
//JButton, button
button.setBounds(25, 25, 100, 60); //<<---- Is this correct?
panel.add(button);
}
}

Is there a better way?
Layout managers, layout managers, layout managers. If the default provided layout managers aren't doing what you want, either use a combination of layout managers or maybe try some of the freely available layout managers, like MigLayout (and use them in combination with other layout managers as required)
With your code...
Using a GridBagLayout
The button is slightly bigger, because it's taking into account the actual requirements of the button (text and font size), but will always add an additional 100 pixels to the width and 60 pixels to the height.
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main {
public static void main(String args[]) {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
JButton button = new JButton("Click");
//JFrame, frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setSize(500, 500);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
//JPanel, panel
panel.setLayout(new GridBagLayout());
frame.add(panel);
GridBagConstraints gbc = new GridBagConstraints();
gbc.ipadx = 100;
gbc.ipady = 60;
gbc.insets = new Insets(25, 25, 0, 0);
gbc.weightx = 1;
gbc.weighty = 1;
gbc.anchor = GridBagConstraints.NORTHWEST;
panel.add(button, gbc);
}
}
Now, if all I do is add button.setFont(button.getFont().deriveFont(64f)); we end up with...
Your code on the left, my code on the right...
And if you think that's been overly dramatic, different OS's will do worse things to you then that

Related

JScrollPane not working correctly when adding JPanel (with FlowLayout) into JScrollPane

I tried to add a JPanel (with FlowLayout) to a JScrollPane but the ScrollBar is not working. I want to place buttons as grid but it places horizontally.
import javax.swing.*;
import java.awt.*;
public class Test {
public static void main(String[] args){
JFrame frame = new JFrame("Test");
frame.setVisible(true);
frame.setSize(1000,500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout(FlowLayout.LEFT));
JScrollPane pane = new JScrollPane(panel);
pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
frame.add(pane);
for (int i=0;i<100;i++){
panel.add(new JButton("Label"));
}
}
}
I want to place buttons as grid but it places horizontally.
That's because you do not set the preferred size of the JPanel and because you add the JPanel to a JScrollPane you are effectively giving the JPanel infinite width and FlowLayout will lay out all its components in a single row until it reaches the width limit of the JPanel but because the width is infinite, all the JButtons appear on the same line. Also, because you set the horizontal scrollbar policy to NEVER, there is no way to scroll the JPanel.
You should call method setVisible(true) after you have added all the components.
Note that in the below code I use GridLayout rather than FlowLayout because FlowLayout will not display a grid of JButton. Also note that I call method pack() rather than method setSize().
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class Test {
public static void main(String[] args) {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(0, 10, 5, 5));
JScrollPane pane = new JScrollPane(panel);
pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
for (int i=0;i<100;i++){
panel.add(new JButton("Label"));
}
frame.add(pane);
frame.pack();
frame.setVisible(true);
}
}
Here is a screen capture:
Note that, by default, JScrollPane will size itself so as to display all the JButtons. If you want the JScrollPane to only display a few rows, then you need to set its preferred size, for example
pane.setPreferredSize(new Dimension(710, 150));
EDIT
If you insist on using FlowLayout then you need to set the preferred size for both the JPanel and the JScrollPane.
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class Test {
public static void main(String[] args) {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(710, 315));
panel.setLayout(new FlowLayout(FlowLayout.LEFT));
for (int i = 0; i < 100; i++) {
panel.add(new JButton("Label"));
}
JScrollPane pane = new JScrollPane(panel);
pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
pane.setPreferredSize(new Dimension(720, 160));
frame.add(pane);
frame.pack();
frame.setVisible(true);
}
}
Here is a screen capture.

JPanel GridBagLayout start from top instead of center

I´ve been trying to make a dashboard where the main menu buttons are listed from top of the dashboard to bottom, but setting
gridBagConstraints.gridx = 10;
gridBagConstraints.gridy = 0;
starts in center of the panel instead at the top. I tried setting gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START and GridBagConstraints.NORT as well as NORTHWEST, but that did nothing.
Since there is a large panel on the side of the menu, I can't have the buttons auto fit into the (the weighty=1 option), otherwise the buttons become elongated.
Is there a way to force the buttons to make a list, or a way of doing this with another layout?
This is a common pattern. Generally, when you want to force the alignment of the components to a particular edge, you place a filler component on the opposite side and set it to fill the remaining empty space
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridwidth = GridBagConstraints.REMAINDER;
frame.add(new JLabel("This is a line"), gbc);
frame.add(new JLabel("This is another line"), gbc);
frame.add(new JLabel("This is show off line"), gbc);
gbc.weighty = 1;
JPanel filler = new JPanel();
filler.setBackground(Color.RED);
frame.add(filler, gbc);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
ps I'd normally make the filler component transparent, but this is for demonstration purposes

Java swing layout, 3 panels

So I'm trying to make my first small java game in my own spare time. I am having trouble with the layout.
I want the game to be a specific size (600 height, 800 width) and I would like 3 "Panels" within the main frame. One which is the main game frame and would be 500 height and 600 width, an inventory/info panel on the right which should have 500 height and 200 width and finally a text panel at the bottom to hold information which would have a height of 100 and a width of 800. So far, here is what I have. (I didn't play around with the panel height as I found nothing changed).
How would I go about making a frame with those 3 panels inside it. I had a look on how to use GridBagLayout() but it seems I have made it worse and do not fully understand how to use it, even with the documentation (yes, im stupid).
LMK if you don't understand parts of my code or my post for that matter. Thank you.
package Frame;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class frame {
//Sets variables such as height, width and title
private JFrame frame;
private Canvas canvas;
private JPanel mainWindow, infoWindow, textWindow;
//main constructor to create the frame of the game. Is called in Launcher
//Sets the parameters of the frame. User defined in main.
public frame(){
createDisplay();
}
//sets the properties of the display
private void createDisplay() {
frame = new JFrame();
frame.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
frame.setTitle("Island Man");
frame.setSize(800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setVisible(true);
canvas = new Canvas();
canvas.setSize(new Dimension(800, 600));
canvas.setMaximumSize(new Dimension(800, 600));
canvas.setMinimumSize(new Dimension(800, 600));
mainWindow = new JPanel();
mainWindow.setBackground(Color.CYAN);
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 0;
c.weightx = 2;
c.weighty = 2;
frame.add(mainWindow, c);
infoWindow = new JPanel();
infoWindow.setBackground(Color.GREEN);
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 3;
c.gridy = 0;
c.weightx = 0;
c.weighty = 2;
frame.add(infoWindow, c);
textWindow = new JPanel();
textWindow.setBackground(Color.MAGENTA);
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 3;
c.gridy = 0;
c.weightx = 0;
c.weighty = 3;
frame.add(textWindow, c);
frame.add(canvas);
frame.pack();
}
}
One way is to use a BorderLayout with the main panel in CENTER, the inventory panel in EAST, and the text panel in SOUTH. Be sure to set the preferred size of each of the panels.
How do I make a frame that has these 3 panels with those dimensions?
There are too many ways to do it. I most direct ways would be setting the size accordingly for each panel and add them to the main panel, then add the main panel to the frame:
The exact Layout to use is dependent on..
how you want your subpanels to be arranged and
how would you want them to react when the frame is resized and
how you want the components in the panels to be arranged.
The following shows one possible way by making use of the FlowLayout.
class MainPanel extends JPanel
{
public MainPanel(){
setPreferredSize(new Dimension(800, 600));
setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
add(new GamePanel());
add(new InventoryPanel());
add(new TextPanel());
}
}
class GamePanel extends Panel
{
public GamePanel(){
setPreferredSize(new Dimension(500, 600));
setBackground(Color.ORANGE);
}
}
class InventoryPanel extends Panel
{
public InventoryPanel(){
setPreferredSize(new Dimension(200, 600));
setBackground(Color.YELLOW);
}
}
class TextPanel extends Panel
{
public TextPanel(){
setPreferredSize(new Dimension(100, 600));
setBackground(Color.CYAN);
}
}
Adding the main panel to the frame:
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
JFrame frame = new JFrame("Game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new MainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

JButton size and JScrollPane not working well together

I am thoroughly confused. I have a pretty decent understanding of how each layout manger works and what each one is used for, but I'm not understanding what combination of layout managers and JPanels are necessary to make what I need work.
What I am trying to accomplish
I have a top bar, and a bottom bar of a container panel NORTH and SOUTH of a BorderLayout.
Within the Center panel, I want an unknown number of buttons 1 or more. Regardless of how many buttons there are they all need to be the same size, if there are dozens then scrolling should start happening once the buttons pass the window size limit.
What I am getting
Depending on the combination of layout mangers and how many nested JPanels I use and all sorts of trouble shooting, I get one massive button filling the entire CENTER element. I get 2 buttons that are the right size, but spread way apart (gap filling the CENTER space), or I get a dozen buttons that are the right size with no scroll.
I can solve any one of these, but then the other breaks. IE if I get a bunch of correctly sized buttons that properly scroll, then when I replace them with a single button its one massive button. Or if I get a single properly sized button then the larger quantity won't scroll etc.
My Code
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.io.*;
public class TestCode extends JFrame {
private final JFrame frame;
public TestCode(){
frame = new JFrame();
JLabel title = new JLabel("Test Title");
JPanel windowContainer = new JPanel();
JPanel topPanel = new JPanel();
final JPanel middlePanel = new JPanel();
JPanel bottomPanel = new JPanel();
JButton searchButton = new JButton("Search");
JButton browseButton = new JButton("Browse...");
JButton testButton = new JButton("Button 1");
JButton exitButton = new JButton("Exit");
final JTextField searchBar = new JTextField("Search database...");
topPanel.setLayout(new GridLayout(2,0));
topPanel.add(title);
title.setHorizontalAlignment(JLabel.CENTER);
topPanel.setPreferredSize(new Dimension(getWidth(), 100));
// This is a subset of the top section. Top part is two panels, bottom panel is two cells (grid)
JPanel topPanelSearch = new JPanel();
topPanelSearch.setLayout(new GridLayout(0,2));
topPanelSearch.add(searchBar);
topPanelSearch.add(searchButton);
topPanel.add(topPanelSearch);
// PROBLEM AREA STARTS
// middlePanel.setLayout(new FlowLayout());
middlePanel.setLayout(new GridLayout(0, 1, 10, 10));
// middlePanel.setLayout(new BoxLayout(middlePanel, BoxLayout.PAGE_AXIS));
JPanel innerContainer = new JPanel();
innerContainer.setLayout(new BoxLayout(innerContainer, BoxLayout.PAGE_AXIS));
// innerContainer.setLayout(new FlowLayout());
// innerContainer.setLayout(new GridLayout(0, 1, 10, 10));
for(int i = 0; i < 2; i++){
JButton button = new JButton("Button ");
button.setPreferredSize(new Dimension(400, 100));
JPanel test = new JPanel();
test.add(button);
innerContainer.add(test);
}
JScrollPane midScroll = new JScrollPane(innerContainer);
middlePanel.add(midScroll);
// PROBLEM AREA ENDS
bottomPanel.setLayout(new GridLayout(0, 3));
bottomPanel.setPreferredSize(new Dimension(getWidth(), 100));
bottomPanel.add(testButton);
bottomPanel.add(browseButton);
bottomPanel.add(exitButton);
windowContainer.setLayout(new BorderLayout());
windowContainer.add(topPanel, BorderLayout.NORTH);
windowContainer.add(middlePanel, BorderLayout.CENTER);
windowContainer.add(bottomPanel, BorderLayout.SOUTH);
frame.add(windowContainer);
frame.setTitle("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(480, 800);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args){
TestCode test = new TestCode();
}
}
Visual of some of the fail results
I want the leftmost picture, but buttons should be stacked neatly (like the middle picture) when there are only a few results, and scrollable when there are lots.
What am I doing wrong?
Try with GridBagLayout and a filler component that takes the remaining vertical space and therefore forces the buttons upwards.
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.Box.Filler;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class GridbagButtons extends JFrame {
private final JScrollPane jscrpButtons;
private final JPanel jpButtons;
public GridbagButtons() {
setLayout(new BorderLayout());
jpButtons = new JPanel(new GridBagLayout());
jscrpButtons = new JScrollPane(jpButtons);
add(jscrpButtons, BorderLayout.CENTER);
// add a custom number of buttons
int numButtons = 10;
for (int i = 0; i < numButtons; i++) {
JButton jbButton = new JButton("Button");
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = i;
jpButtons.add(jbButton, gbc);
}
// add a vertical filler as last component to "push" the buttons up
GridBagConstraints gbc = new GridBagConstraints();
Filler verticalFiller = new Filler(
new java.awt.Dimension(0, 0),
new java.awt.Dimension(0, 0),
new java.awt.Dimension(0, Integer.MAX_VALUE));
gbc.gridx = 0;
gbc.gridy = numButtons;
gbc.fill = java.awt.GridBagConstraints.VERTICAL;
gbc.weighty = 1.0;
jpButtons.add(verticalFiller, gbc);
setSize(300, 200);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new GridbagButtons().setVisible(true);
}
});
}
}

How to give a preffered size to the JButton?

import javax.swing.*;
import java.awt.*;
class MainGui{
JFrame frame = new JFrame();
JPanel mainPanel = new JPanel();
JButton newBut = new JButton("New Game");
JButton continueBut = new JButton("Continue");
JButton exitBut = new JButton("Exit");
JLabel backImage = new JLabel(new ImageIcon("C:\\Users\\BSK\\Desktop\\game5.jpg"));
public MainGui(){
frame.setSize(600,800);
frame.setVisible(true);
frame.setResizable(false);
setButtonSize();
frame.setLayout(new BorderLayout());
frame.setContentPane(backImage);
frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(),BoxLayout.Y_AXIS));
insertBlankArea(frame);
frame.getContentPane().add(newBut);
insertBlankArea(frame);
frame.getContentPane().add(continueBut);
insertBlankArea(frame);
frame.getContentPane().add(exitBut);
frame.setSize(799,800);
}
public void insertBlankArea(JFrame frame){
frame.getContentPane().add(Box.createRigidArea(new Dimension(280,155)));
}
public void setButtonSize(){
Dimension dim = new Dimension(100,100);//here is the problem,i am not getting the desired dimension and the size of buttons remains the default.
newBut.setPreferredSize(dim);
continueBut.setPreferredSize(dim);
exitBut.setPreferredSize(dim);
}
public static void main(String[] args) {
MainGui mainGui = new MainGui();
}
}
So iam not getting the defined size for the buttons but when i set frame.setResizable(false); then when i stretch the screen the button's height increases but its width still remains the same.
So please tell me what is going wrong?
You should take a look at A Visual Guide to Layout Managers and choose the most appropriate one for your situation. You should also avoid explicitly setting sizes (ie: setSize, setMinimumSize, setMaximumSize, and setPreferredSize) because those methods are the responsibility of the layout manager. You may also be interested in reading this question on whether or not the use of the different set size methods should be avoided or not.
Finally, you should not be calling your MainGUI class outside of the Event Dispatch Thread (EDT). Most Swing GUI-related methods are not thread safe and therefore require being executed in the EDT. Below is a corrected version of your main method:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
MainGui mainGui = new MainGui();
}
});
}
Just reading your short descrption, I have no idea what your problem is. But based solely on the question title
"How to give a preffered size to the JButton?"
Don't. Let the the layout manager handle this for you. If you want a bigger button, you can use JButton.setMargins(Insets) and/or JButton.setFont(Font) where you specify a bigger font.
If you want you button stretched or not to stretch, You need to select an appropriate layout manager, that will or won't respect the buttons preferred size. For instance, BorderLayout and GridLayout won't respect preferred sizes and will stretch the button the fit, and FlowLayout, BoxLayout, and GridBagLayout will respect the preferred size. As you can see here
See example with GridBagLayout
import javax.swing.*;
import java.awt.*;
class MainGui {
JFrame frame = new JFrame();
JPanel mainPanel = new JPanel();
JButton newBut = new JButton("New Game");
JButton continueBut = new JButton("Continue");
JButton exitBut = new JButton("Exit");
JLabel backImage = new JLabel(new ImageIcon(
getClass().getResource("images.jpg")));
public MainGui() {
backImage.setLayout(new BorderLayout());
frame.setContentPane(backImage);
JPanel mainPanel = new JPanel(new GridBagLayout());
mainPanel.setOpaque(false);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridy = 0;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
mainPanel.add(newBut, gbc);
gbc.gridy = 1;
mainPanel.add(continueBut, gbc);
gbc.gridy = 2;
mainPanel.add(exitBut, gbc);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(mainPanel);
frame.setSize(250, 275);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
MainGui mainGui = new MainGui();
}
});
}
}
And here's with nesting panels which will give the same result
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
class MainGui {
JFrame frame = new JFrame();
JPanel mainPanel = new JPanel();
JButton newBut = new JButton("New Game");
JButton continueBut = new JButton("Continue");
JButton exitBut = new JButton("Exit");
JLabel backImage = new JLabel(new ImageIcon(
getClass().getResource("images.jpg")));
public MainGui() {
backImage.setLayout(new GridLayout(3,1));
frame.setContentPane(backImage);
JPanel p1= new JPanel(new GridBagLayout());
p1.setOpaque(false);
p1.add(newBut);
JPanel p2 = new JPanel(new GridBagLayout());
p2.setOpaque(false);
p2.add(continueBut);
JPanel p3 = new JPanel(new GridBagLayout());
p3.setOpaque(false);
p3.add(exitBut);
frame.add(p1);
frame.add(p2);
frame.add(p3);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(250, 275);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
MainGui mainGui = new MainGui();
}
});
}
}

Categories