简体   繁体   English

无法使按钮位于中央右位置

[英]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. 我试图了解如何确定我想要在Swing中的位置,但我真的无法理解每种布局的优势。

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

    }

}

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. 布局管理器现在为null ,因为JLabel实际上没有默认的布局管理器。

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. 因此,“简单”的答案是将setLayout调用移到setContentPane调用之下,但这是一个短视的答案,因为JLabel仅根据icon和text属性而不是子组件的内容来计算它的优先级。

A better solution would be to do something demonstrated in How to set a background picture in JPanel (see the second example) 更好的解决方案是执行如何在JPanel中设置背景图片中演示的操作(请参见第二个示例)

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 我仔细检查并清理了代码,只是为了使布局正常工作

布局简单

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. 我还想指出,直接从JFrame扩展也是近距离的,它将您锁定在一个一次性容器中,并且实际上并没有向该类添加任何新功能。

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
                }
            }

        }

    }

}

A better way to add a BG image is to use a custom painted JPanel . 添加BG图像的更好方法是使用自定义绘制的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 . 请注意,此处的按钮主要是因为已添加到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). 这是一种沿相同方向工作的替代方法,红色面板是自定义绘制背景图像的面板, menu面板设置为透明(寻找opaque方法)。

在此处输入图片说明

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

Doing UI in Java is not advised, but ignoring that. 不建议在Java中使用UI,但请忽略这一点。

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. 在屏幕上画一个按钮,其像素值宽度的50%和像素值高度的50%将使按钮居中。

Simply crate buttons with variable location that is calculated from main screen px size and place them where ever you want. 只需将根据主屏幕px尺寸计算出的位置可变的按钮包装起来,然后将它们放置在所需的位置即可。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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