简体   繁体   中英

JAVA GUI - How to reproduce my GUI with a layout manager?

I am using a simple Main Menu for my application, however the problem is that it is all hard coded using layout=null and not being resizeable.

Since this is really really bad practice, I wanted to go head with some layout manager.

Even though since it is not resizable, there should not be issues, but still it feels wrong.

It looks like this : https://i.imgur.com/k1Ne5v9.png

and the code for it is:

public class MainMenu {
private static JFrame mF = new JFrame("Main Menu");

public static void main(String[] args) {
    System.setProperty("sun.java2d.cmm", "sun.java2d.cmm.kcms.KcmsServiceProvider");

    Font menuFont = new Font("Courier",Font.BOLD,16);
    mF.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    mF.setSize(465,230);
    mF.setLocationRelativeTo(null);
    mF.getContentPane().setBackground(Color.WHITE);

    Color blueSteel = new Color(70,107,176);
    JPanel p = new JPanel();
    p.setSize(600,50);
    p.setLayout(new GridBagLayout());
    GridBagConstraints gbc = new GridBagConstraints();
    p.setLocation((mF.getWidth() - p.getWidth()) /2, 20);
    p.setBackground(blueSteel);
    JLabel l = new JLabel("Welcome to the menu GENERATORRRR");
    l.setFont(menuFont);
    l.setForeground(Color.WHITE);
    p.add(l, gbc);

    JButton runMenuButt = new JButton("Generate Menu");
    runMenuButt.setLocation(20 , 90);
    JButton manageRecipButt = new JButton("Manage Recipients");
    manageRecipButt.setLocation(240 , 90);
    menuUtilities.formatButton(runMenuButt);
    menuUtilities.formatButton(manageRecipButt);

    mF.setResizable(false);
    mF.setLayout(null);
    mF.add(runMenuButt);
    mF.add(manageRecipButt);
    mF.add(p);
    mF.setVisible(true);

    runMenuButt.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            System.out.println("Generate Menu pressed");
            mF.dispose();
            getMenuInJavaNow.main();
            //MenuGenerator.generateTheMenu();
        }
    });

    manageRecipButt.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            DeliveryPackage menuRecipients = new DeliveryPackage();
            if (menuRecipients.recipientList != menuRecipients.fileNotFoundMessage) {
                editRecipientList(menuRecipients);
            } else {
                JOptionPane.showMessageDialog(null,"File not found at " + menuRecipients.recipientFilePath ,menuRecipients.recipientFileName + " missing!" ,JOptionPane.ERROR_MESSAGE);
            }
        }
    });

}

How could I convert this into GUI that uses some layout manager? Also I dont mind if you point out any mistakes/bad practices used in the code, because I am self-taught and I would definitely like to avoid them in the future.

Thank you for your time

I have done your layout using layout managers and i have added comments inside the code about the how and why i prefer things like this. However, layout managers need practice in order be able to handle them fast and easy. Just don't avoid to use them.

Please, have in mind that all of these are personal preferences. You can keep what you like and ignore what you don't.

Here it is:

Main class:

package test;

import javax.swing.SwingUtilities;

public class Main {
    /*
     * Having a static JFrame is only recommended when you know exactly what you are
     * doing. 99% of the times (i could say 100% :)) you will never need it.
     */
    // private static JFrame mF = new JFrame("Main Menu");

    public static void main(String[] args) {
        System.setProperty("sun.java2d.cmm", "sun.java2d.cmm.kcms.KcmsServiceProvider");
        /*
         * All Swing applications must run on their own thread, a.k.a Event Dispatch
         * Thread (EDT). I also like to use main method separated from GUI
         * methods/classes.
         */
        SwingUtilities.invokeLater(() -> {
            MyFrame frame = new MyFrame();
            // It is recommended to show the frame (make it visible) after its initiated and
            // not in its constructor
            frame.setVisible(true);
        });
    }
}

MyFrame class:

package test;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingConstants;

public class MyFrame extends JFrame {
    private static final long serialVersionUID = -5908534022988507382L;
    // Things like colours,fonts, dimensions or thing that won't change, i recommend
    // them to define them as static
    private static final Font FONT = new Font("Courier", Font.BOLD, 16);
    private static final Color BLUE_STEEL = new Color(70, 107, 176);
    private static final Dimension INITIAL_SIZE = new Dimension(500, 250);
    private static final Dimension MINIMUM_SIZE = new Dimension(300, 200);

    public MyFrame() {
        // Now start the standard things for a frame.
        super("Main Menu");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        getContentPane().setBackground(Color.WHITE);
        // setSize(465, 230); // Initial size. Do not use setSize() for other
        // components. Only for frames.

        /*
         * Now depends how you want the GUI, you choose the layout manager. In your
         * uploaded picture you showed a TextField/JLabel at the top and 2 buttons in
         * the center. You can always go either with GridBag layout, or as i like to go,
         * with inherited panels.
         */
        /*
         * In order to learn layout managers, read the java docs. For now i will show
         * you how to use 2 of them.
         */
        /*
         * JFrame's content pane uses either FlowLayout, either BorderLayout initially.
         * For me, i don't actually care, i will define it anyways, so when i'll see the
         * code i will be able to see easily the layout. A personal preference aswell.
         */
        /*
         * Read BorderLayout java doc in order to see how it works.
         */
        getContentPane().setLayout(new BorderLayout(1, 15)); // 15 pixels vertical gap
        /*
         * Try to describe the variable fully. Personally, i use the "txt" for simple
         * texts that won't change during runtime.
         */
        JLabel txtWelcome = new JLabel("Welcome to the menu GENERATORRRR");
        txtWelcome.setFont(FONT);
        txtWelcome.setHorizontalAlignment(SwingConstants.CENTER);// Centrize text
        txtWelcome.setForeground(Color.WHITE);
        txtWelcome.setBackground(BLUE_STEEL);
        /*
         * I describe with few words about heights and dimensions in
         * createMainButtonsPanel() method. This is the one line :)
         */
        txtWelcome.setPreferredSize(
                new Dimension(txtWelcome.getPreferredSize().width, txtWelcome.getPreferredSize().height + 15));
        /*
         * Since you want white foreground and blue background, the component must have
         * opacity. In our case, it is a JLabel which is not opaque initially.
         */
        txtWelcome.setOpaque(true);
        getContentPane().add(txtWelcome, BorderLayout.PAGE_START);// at the top

        /*
         * Now let's add the 2 buttons. For this, we are going to use an inhertied panel
         * inside the content pane.
         */
        JPanel mainButtonsPanel = createMainButtonsPanel();
        getContentPane().add(mainButtonsPanel, BorderLayout.CENTER); // at the center
        setSize(INITIAL_SIZE); // The initial frame size
        setMinimumSize(MINIMUM_SIZE);
    }

    /*
     * Use a different method for this panel creation, it will be easier to read the
     * code later.
     */
    private JPanel createMainButtonsPanel() {
        JPanel panel = new JPanel();
        /* Components at center with 20pixels gap horizontally */
        panel.setLayout(new FlowLayout(FlowLayout.CENTER, 20, 1));
        /*
         * Panel's bg color is the initial color, if you want to have the background
         * color of the frame, must have no opacity.
         */
        panel.setOpaque(false);
        JButton runMenuButton = new JButton("Generate Menu");
        runMenuButton.setFont(FONT); // In case you want the font
        /*
         * Adding an actionlistener using an Anonymous inner class is fine. However, if
         * you use java8+ i would recommend you to go with lamdas since code will look
         * more clear.
         */
        runMenuButton.addActionListener(e -> {
            System.out.println("Generate Menu pressed");
            // Do more stuff here
        });

        JButton manageReceiptsButton = new JButton("Manage Receipts");
        manageReceiptsButton.setFont(FONT);
        manageReceiptsButton.addActionListener(e -> {
            JOptionPane.showMessageDialog(panel, "Manage Receipts pressed.");
            // Do more stuff here
        });
        /*
         * Now let's handle their height. Flow layout will add them with their initially
         * height. Initial height changes when you use bigger font/bigger icon, but if
         * you don't want to use a bigger font you have to increase the height manually.
         * Other layout managers would increase their height in order fit the whole
         * panel. I will add them some height directly, but its preferred to use the
         * extra height as a static field.
         */
        int extraHeight = 15;
        runMenuButton.setPreferredSize(new Dimension(runMenuButton.getPreferredSize().width,
                runMenuButton.getPreferredSize().height + extraHeight));
        manageReceiptsButton.setPreferredSize(new Dimension(manageReceiptsButton.getPreferredSize().width,
                manageReceiptsButton.getPreferredSize().height + extraHeight));
        /*
         * Now add them to the panel. I usually add them in the end of the method,
         * because it will be easier later to change their position. E.g: you might want
         * the manage receipts button first and then the generate menu button. So, it
         * will take you just 1 sec to change 2 lines. Adding them after they are
         * initialized is fine aswell.
         */
        panel.add(runMenuButton);
        panel.add(manageReceiptsButton);
        return panel;
    }
}

Ps: Ignore if some numbers are not equal to yours (heights and sizes). I have just giving you an example :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM