JE Krupat
JE Krupat

Reputation: 91

Java Swing: Trying to get a button to center

I'm trying to make a login page for an idea I'm working on and am trying to center two buttons. When I get the screen dimensions and divide them by 2 it is not centered. Here's my code:

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

public class ChatWindow extends JFrame {

    public ChatWindow() {
        JFrame frame = new JFrame("EasyChat");
        JButton login = new JButton("Login");
        JButton signup = new JButton("Don't have an account? Sign Up");
        JPanel mainPanel = new JPanel();
        Dimension ss = Toolkit.getDefaultToolkit().getScreenSize();

        frame.setVisible(true);
        frame.setLayout(null);
        frame.setSize(800,450);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
        
        frame.getContentPane().add(login);
        frame.getContentPane().add(signup);
        
        login.setPreferredSize(new Dimension(25,60));
        login.setFont(new Font("HelveticaNeue", Font.BOLD, 20));
        signup.setBounds(ss.width / 2, ss.height / 2 + 125, 200, 100);
        login.setBounds(ss.width / 2, ss.height / 2, 200, 100); 
        
        mainPanel.setLayout(new BorderLayout());
        mainPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
    }
    
    
}

I also want to know how to make the buttons stayed centered if the user exits fullscreen mode.

Thank you.

Upvotes: 1

Views: 997

Answers (3)

Andrew Thompson
Andrew Thompson

Reputation: 168845

enter image description here

This answer seems to use the (first) approach detailed by MadProgrammer, but since I have it ready.

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

public class CenteredButtons {

    public CenteredButtons() {
        JFrame f = new JFrame("Centered Buttons");
        // A FlowLayout might also be used here
        // Doing so would allow each button to be its natural size
        JPanel buttonPanel = new JPanel(new GridLayout(1,0,20,20));
        buttonPanel.add(new JButton("Yes"));
        buttonPanel.add(new JButton("No"));
        buttonPanel.setBorder(new EmptyBorder(30,75,30,75));

        // a component (e.g. buttonPanel) added with no constraints will be centered
        JPanel centerPanel = new JPanel(new GridBagLayout());
        centerPanel.add(buttonPanel);
        f.setContentPane(centerPanel);

        f.pack(); // validates the layout and sets a size for the frame
        f.setLocationRelativeTo(null); // centers the window on the screen
        f.setExtendedState(JFrame.MAXIMIZED_BOTH); // maximizes the window
        f.setVisible(true);
    }

    public static void main(String[] args) {
        Runnable r = () -> new CenteredButtons();
        SwingUtilities.invokeLater(r);
    }
}

Upvotes: 2

MadProgrammer
MadProgrammer

Reputation: 347334

Make use of the available layout managers. See Laying Out Components Within a Container for more details

For simplicity, I've just use GridBagLayout as this will centre the components within the container by default

enter image description hereenter image description here

And you get resisability for free

import java.awt.EventQueue;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

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.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setBorder(new EmptyBorder(16, 16, 16, 16));
            setLayout(new GridBagLayout());
            add(new JButton("Login"));
            add(new JButton("Sign Up"));
        }

    }
}

Now, if you want the buttons to be the same, you might be able to get it to work using something like GridLayout,

enter image description here

import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

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.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setBorder(new EmptyBorder(32, 32, 32, 32));
            setLayout(new GridBagLayout());

            JPanel buttonPane = new JPanel(new GridLayout(1, -1));
            buttonPane.add(new JButton("This is a long button"));
            buttonPane.add(new JButton("Sign Up"));

            add(buttonPane);
        }

    }

}

Or you could use a custom layout manager, for example...

enter image description here

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Insets;
import java.awt.LayoutManager2;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

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.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setBorder(new EmptyBorder(32, 32, 32, 32));
            setLayout(new ButtonLayoutManager());
            add(new JButton("This is a long button"));
            add(new JButton("Sign Up"));
        }

    }

    public class ButtonLayoutManager implements LayoutManager2 {

        private int horizontalPadding = 0;

        @Override
        public void addLayoutComponent(Component comp, Object constraints) {
        }

        @Override
        public void addLayoutComponent(String name, Component comp) {
        }

        @Override
        public void removeLayoutComponent(Component comp) {
        }

        @Override
        public void invalidateLayout(Container target) {
        }

        @Override
        public Dimension maximumLayoutSize(Container target) {
            return preferredLayoutSize(target);
        }

        @Override
        public Dimension minimumLayoutSize(Container parent) {
            return preferredLayoutSize(parent);
        }

        @Override
        public Dimension preferredLayoutSize(Container parent) {
            int height = 0;
            int width = 0;
            for (Component comp : parent.getComponents()) {
                height = Math.max(comp.getPreferredSize().height, height);
                width = Math.max(comp.getPreferredSize().width, width);
            }

            width = (width * parent.getComponentCount()) + (horizontalPadding * parent.getComponentCount() - 1);

            Insets insets = parent.getInsets();

            width += insets.left + insets.right;
            height += insets.top + insets.bottom;

            return new Dimension(width, height);
        }

        @Override
        public float getLayoutAlignmentX(Container target) {
            return 0.5f;
        }

        @Override
        public float getLayoutAlignmentY(Container target) {
            return 0.5f;
        }

        @Override
        public void layoutContainer(Container parent) {
            int width = parent.getWidth();
            int height = parent.getHeight();

            Insets insets = parent.getInsets();

            int maxWidth = 0;
            int maxHeight = 0;
            for (Component comp : parent.getComponents()) {
                maxWidth = Math.max(comp.getPreferredSize().width, maxWidth);
                maxHeight = Math.max(comp.getPreferredSize().height, maxHeight);
            }

            int padding = (horizontalPadding * parent.getComponentCount() - 1);
            int totalWidth = padding + (maxWidth * parent.getComponentCount());

            int yOffset = (height - maxHeight) / 2;
            int xOffset = (width - totalWidth)  / 2;

            for (Component comp : parent.getComponents()) {
                comp.setBounds(xOffset, yOffset, maxWidth, maxHeight);
                xOffset += horizontalPadding + maxWidth;
            }
        }

    }
}

nb: I've not done extensive testing on this and is only meant for demonstration purposes

Upvotes: 3

M. Gianota
M. Gianota

Reputation: 184

You need to subtract half the width and half the height of each of the buttons from the screen dimensions to center the two widgets.

Change the code where you set the bounds on the buttons to the following:

        signup.setBounds(ss.width / 2 - 200 / 2, ss.height / 2 + 125 - 100 / 2, 200, 100);
        login.setBounds(ss.width / 2 - 200 / 2, ss.height / 2 - 100 / 2, 200, 100);

To be notified when the user exits full screen mode, add a WindowStateListener to the frame and reset the bounds on the buttons. Here's the complete code:

import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowEvent;
import java.awt.event.WindowStateListener;

public class ChatWindow extends JFrame implements WindowStateListener{
    Dimension ss;
    JButton login;
    JButton signup;
    JFrame frame;

    public ChatWindow() {
        frame = new JFrame("EasyChat");
        frame.addWindowStateListener(this);
        login = new JButton("Login");
        signup = new JButton("Don't have an account? Sign Up");
        JPanel mainPanel = new JPanel();
        ss = Toolkit.getDefaultToolkit().getScreenSize();

        frame.setVisible(true);
        frame.setLayout(null);
        frame.setSize(800,450);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setExtendedState(JFrame.MAXIMIZED_BOTH);

        frame.getContentPane().add(login);
        frame.getContentPane().add(signup);

        login.setPreferredSize(new Dimension(25,60));
        login.setFont(new Font("HelveticaNeue", Font.BOLD, 20));
        signup.setBounds(ss.width / 2 - 200 / 2, ss.height / 2 + 125 - 100 / 2, 200, 100);
        login.setBounds(ss.width / 2 - 200 / 2, ss.height / 2 - 100 / 2, 200, 100);

        mainPanel.setLayout(new BorderLayout());
        mainPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
    }
    public static void main(String[] args) {
        new ChatWindow();
    }

    @Override
    public void windowStateChanged(WindowEvent e) {
        Dimension ss = frame.getSize();
        signup.setBounds(ss.width / 2 - 200 / 2, ss.height / 2 + 125 - 100 / 2, 200, 100);
        login.setBounds(ss.width / 2 - 200 / 2, ss.height / 2 - 100 / 2, 200, 100);

    }
}

Upvotes: -2

Related Questions