Avishai Yaniv
Avishai Yaniv

Reputation: 410

Can't get the buttons to be on the center right position

I'm trying to figure out how to position my buttons in the center right position. I added what Ive done so far and I'll add a drawing of how I want it to be.

I'm trying to understand how to determine the position I want in Swing, can't really understand the advantages of each layout.

My code so far:

package Game;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.Timer;


public class MainWindow extends JFrame implements ActionListener {

    private JButton exit;
    private JButton start_Game;
    private ImageIcon puzzleBackground;
//  private JLabel back_Label;
//  private GridBagConstraints grid = new GridBagConstraints();
    private JPanel menu;

    public MainWindow() 
    {
        super("Welcome");
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        setSize(450,300);
        setLocationRelativeTo(null);
        this.setLayout(new FlowLayout(FlowLayout.RIGHT));
        menu = new JPanel();
        menu.setLayout(new BorderLayout());
        //setResizable(false);

        //===== Background =====
        puzzleBackground = new ImageIcon("MyBackground.jpg");
        setContentPane(new JLabel(puzzleBackground));

        exit = new JButton("Exit");
        menu.add(exit, BorderLayout.CENTER);
        exit.addActionListener(this);

        start_Game = new JButton("Start to play");
        menu.add(start_Game, BorderLayout.SOUTH);
        exit.addActionListener(this);
        start_Game.addActionListener(this);

//      
//      back_Label = new JLabel(puzzleBackground);
//      back_Label.setLayout(new BorderLayout());

        //===== Buttons =====
//      back_Label.add(exit,BorderLayout.CENTER);
//      
//      back_Label.add(start_Game,BorderLayout.EAST);
//      
        add(menu);
        setVisible(true);
    }


    public static void main(String args[])
    {
        MainWindow a = new MainWindow();
    }
    @Override
    public void actionPerformed(ActionEvent e) {
        if(e.getSource() == exit)
        {
            System.exit(0);
        }
        else
        {
            //open start up window.
        }

    }

}

Upvotes: 0

Views: 56

Answers (3)

MadProgrammer
MadProgrammer

Reputation: 347184

So, your basic problem boils down the following lines...

this.setLayout(new BorderLayout());
//...

//===== Background =====
puzzleBackground = new ImageIcon("MyBackground.jpg");
setContentPane(new JLabel(puzzleBackground));

Can you tell me what the layout manager in use actually is now? Wrong. The layout manager is now null, because JLabel doesn't actually have a default layout manager.

So, the "simple" answer would be to move the setLayout call to below the setContentPane call, but this would be a short sighted answer, as JLabel calculates it's preferred based on the icon and text properties only, not it's contents of child components.

A better solution would be to do something demonstrated in How to set a background picture in JPanel (see the second example)

This means that if the image is smaller then the required space, the components will disappear off the screen.

I went through and cleaned up the code slightly, only with the intention of getting the layout to work

Simple layout

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class MainWindow extends JFrame implements ActionListener {

    private JButton exit;
    private JButton start_Game;
    private JPanel menu;

    public MainWindow() {
        super("Welcome");
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        setLocationRelativeTo(null);
        this.setLayout(new BorderLayout());
        menu = new JPanel();
        menu.setLayout(new GridBagLayout());

        exit = new JButton("Exit");
        exit.addActionListener(this);

        start_Game = new JButton("Start to play");
        exit.addActionListener(this);
        start_Game.addActionListener(this);

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.weightx = 1;
        gbc.fill = gbc.HORIZONTAL;
        gbc.gridwidth = GridBagConstraints.REMAINDER;
        menu.add(exit, gbc);
        menu.add(start_Game, gbc);

        // This is just a filler, it can be removed, but it helps prove the point

        add(new JPanel() {
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 200);
            }
        });

        add(menu, BorderLayout.EAST);
        pack();
        setVisible(true);
    }

    public static void main(String args[]) {
        MainWindow a = new MainWindow();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == exit) {
            System.exit(0);
        } else {
            //open start up window.
        }

    }

}

I'd also like to point out that extending directly from JFrame is also short sighted, it's locking you into a single use container and you're not actually adding any new functionality to the class.

Example of better structure...

The following is a simple example of a possibly better structure. It's missing the concept of a "controller", which controls stuff and "model" which maintains the state information which is used by the UI to display "stuff", but gives a starting point

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Main {

    public static void main(String args[]) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Welcome");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new MainPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class MainPane extends JPanel {

        public MainPane() {
            setLayout(new BorderLayout());
            // This is just a filler, it can be removed, but it helps prove the point
            add(new JPanel() {
                @Override
                public Dimension getPreferredSize() {
                    return new Dimension(200, 200);
                }
            });

            add(new MenuPane(), BorderLayout.EAST);
        }

    }

    public class MenuPane extends JPanel {

        private JButton exit;
        private JButton start_Game;
        private JPanel menu;

        public MenuPane() {
            menu = new JPanel();
            menu.setLayout(new GridBagLayout());

            ActionHandler actionHandler = new ActionHandler();

            exit = new JButton("Exit");
            exit.addActionListener(actionHandler);

            start_Game = new JButton("Start to play");
            start_Game.addActionListener(actionHandler);

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.weightx = 1;
            gbc.fill = gbc.HORIZONTAL;
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            menu.add(exit, gbc);
            menu.add(start_Game, gbc);
        }

        public class ActionHandler implements ActionListener {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (e.getSource() == exit) {
                    System.exit(0);
                } else {
                    //open start up window.
                    // This should be used to notifiy a controller class
                    // that some new action needs to take place, the controller
                    // is then responsible for making it happen
                }
            }

        }

    }

}

Upvotes: 1

Andrew Thompson
Andrew Thompson

Reputation: 168815

A better way to add a BG image is to use a custom painted JPanel. Then set the layout of the panel and add other panels or components to it. Note that here the buttons are not appearing largely because they are being added to a JLabel.

Here is an alternative that works along the same lines, with the red panel being the panel which custom paints the background image and the menu panel being set to transparent (look for the opaque method).

enter image description here

import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
import javax.swing.border.*;

public class MainWindow extends JFrame {

    private JPanel menu;
    private JPanel contentPane = new JPanel(new BorderLayout(4,4));

    public MainWindow() {
        super("Welcome");
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        //setSize(450, 300); // use pack() instead
        setContentPane(contentPane);
        contentPane.setBorder(new EmptyBorder(8,8,8,8));
        contentPane.setBackground(Color.RED);
        contentPane.add(new JLabel(new ImageIcon(
                new BufferedImage(400,200,BufferedImage.TYPE_INT_RGB))));

        menu = new JPanel(new GridLayout(0,1,10,10));

        menu.add(new JButton("Exit"), BorderLayout.CENTER);
        menu.add(new JButton("Start to play"), BorderLayout.SOUTH);

        JPanel menuCenterPanel = new JPanel(new GridBagLayout());
        menuCenterPanel.add(menu);
        add(menuCenterPanel, BorderLayout.LINE_END);

        pack();
        setLocationRelativeTo(null); // do AFTER pack()
        setMinimumSize(getSize());
        setVisible(true);
    }

    public static void main(String args[]) {
        MainWindow a = new MainWindow();
    }
}

Upvotes: 1

MartinsB
MartinsB

Reputation: 1

Doing UI in Java is not advised, but ignoring that.

You get (calculate) the height and width of the screen. Then start drawing buttons depending on that. Drawing a button on screens 50% of pixel value width and 50% of pixel value of height will center the button.

Simply crate buttons with variable location that is calculated from main screen px size and place them where ever you want.

Upvotes: -1

Related Questions