【问题标题】:Problem with Java GridLayout and adding ButtonsJava GridLayout 和添加按钮的问题
【发布时间】:2019-03-19 04:23:13
【问题描述】:

我想在GridLayout 中添加 100 个按钮,我的代码可以工作,但有时它只添加一个按钮,如果我点击其他按钮所属的位置,我点击的按钮就会出现。 它完全随机发生,我不明白。 这是我的代码:

    public class GamePanel extends JPanel {
    GameUI controler;
    GridLayout gameLayout = new GridLayout(10,10);
    JButton gameButtons[] = new JButton[100];
    ImageIcon ice;
    JButton startButton;
    JButton exitButton;
    ImageIcon startIcon;
    ImageIcon exitIcon;
    URL urlIcon;
    private int i;

    public GamePanel(GameUI controler) {
        this.setLayout(gameLayout);
        this.controler = controler;
        urlIcon = this.getClass().getResource("/icons/Overlay.png");
        ice = new ImageIcon(urlIcon);
        makeButtons();
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
    }

    public void makeButtons() {
        for(i = 0; i< 100; i++) {
            gameButtons[i] = new JButton(ice);
            this.add(gameButtons[i]);
            revalidate();   
        }
        repaint();
    }
}

更新:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.net.URL;


public class GameUI extends JFrame {

ImageIcon i;
Image jFrameBackground;
JButton startButton;
JButton exitButton;
ImageIcon startIcon; 
ImageIcon exitIcon;


public GameUI() {
    setResizable(false);
    this.setSize(1200, 800);
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    this.setLayout(null);








    BackGroundPanel backGroundPanel = new BackGroundPanel();
    GamePanel panel = new GamePanel(this);
    ButtonPanel buttonPanel = new ButtonPanel();

    panel.setSize(500,500);
    panel.setLocation(100, 150);
    backGroundPanel.setSize(this.getWidth(),this.getHeight());
    backGroundPanel.setLocation(0,0);
    buttonPanel.setSize(390,50);
    buttonPanel.setLocation(100,100);
    this.add(backGroundPanel);
    this.add(panel);
    this.add(buttonPanel);




    backGroundPanel.setBackground(Color.BLACK);



}





public static void main(String[] args) throws InvocationTargetException, InterruptedException {







    javax.swing.SwingUtilities.invokeAndWait(
                new Runnable(){

                    @Override
                    public void run() {



                        GameUI ui = new GameUI();
                        ui.setVisible(true);


                    }


                }

            );




}

}

【问题讨论】:

  • 您发布的代码不包含minimal reproducible example,我们可以编译、运行和测试的代码,包括一个主要方法,所以我不得不猜测。 也许你在别处得到了不恰当地调用超级的绘画方法的绘画代码。 也许在添加所有组件并在其上调用 setVisible(true) 之后,您不会在顶级窗口(通常是 JFrame)上调用 pack()。请注意,您需要在 for 循环之后调用 revalidate(),而不是在其中调用,尽管这不会解决您的问题。
  • 旁注 2:您几乎永远不会想要覆盖 JPanel 的 paint(...) 方法,而是想要覆盖 paintComponent(...) 尽管这在这里无关紧要,因为您的绘制方法正在执行什么都没有。
  • 旁注 3:您不会希望您的 GUI 类实现您的侦听器接口,因为这会给类带来太多责任——请阅读“single-responsibility principle”。我已从您发布的代码中删除了 implements... 声明,因为它与您的问题无关,但我觉得有必要传递我认为对您未来代码很重要的建议。同样,请考虑改进这个问题和您发布的代码,以便它实际上是可以回答的,而无需我们进行猜测。
  • 所以我添加了创建 jpanel 的位置,希望对您有所帮助。无论如何,游戏面板类不是 gui 类,按钮应该是“沉船”的游戏元素。如果我在paint方法中添加按钮,它不会与paintComponent一起使用。我试图添加 pack() 但它不起作用它只是将我的 jframe 缩小到最小。
  • 1) 组件应在框架可见之前添加到框架中 2) 不需要 revalidate() 和 repaint(),因为面板尚未添加到框架中。您只需在将组件添加到可见 GUI 之后调用这些方法。但是在您的情况下,代码是从构造函数执行的,因此不需要它们。

标签: java swing panel layout-manager grid-layout


【解决方案1】:

正如我在 cmets 中提到的,您使用的是空布局,这就是问题的根源。

您正在使用 null 布局尝试将 JPanel 分层,一个在另一个之上,这不是它应该如何使用或它的用途,也不是您应该如何创建背景。这具有背景覆盖您的按钮的效果,直到您的鼠标悬停在它们上方。

如果您想创建背景图片,我建议您:

  • 创建一个JPanel,比如说叫BackgroundPanel,
  • 重写它的paintComponent方法,
  • 在方法的第一行调用它的super.paintComponent(g);
  • 然后绘制它应该显示的图像
  • 然后给它一个像样的布局管理器
  • 向其中添加您的 GUI 组件
  • 确保通过.setOpaque(false) 将任何添加到其中的 JPanel 设为透明

其他选项包括使用 JLayeredPane,但您真的不需要它来获得背景。

例如,以下代码产生:

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;

public class GameUI2 {

    private static final String IMG_PATH = "https://upload.wikimedia.org/wikipedia/commons/3/3f/"
            + "Butterfly_Nebula_in_narrow_band_Sulfur%2C_Hydrogen_and_Oxygen_Stephan_Hamel.jpg";
    private static final String BTN_IMG_PATH = "https://upload.wikimedia.org/wikipedia/commons/5/54/Crystal_Project_Games_kids.png";

    private static void createAndShowGui() {
        BufferedImage bgImg = null;
        BufferedImage btnImg = null;
        try {
            URL bgImgUrl = new URL(IMG_PATH);
            URL btnImgUrl = new URL(BTN_IMG_PATH);
            bgImg = ImageIO.read(bgImgUrl);
            btnImg = ImageIO.read(btnImgUrl);
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(-1);
        }


        BackgroundPanel2 mainPanel = new BackgroundPanel2(bgImg);
        mainPanel.setLayout(new GridBagLayout());
        GamePanel2 gamePanel = new GamePanel2(btnImg); 
        mainPanel.add(gamePanel);        

        JFrame frame = new JFrame("Game");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.setResizable(false);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}

@SuppressWarnings("serial")
class BackgroundPanel2 extends JPanel {
    private Image backgroundImg;

    public BackgroundPanel2(Image backgroundImg) {
        this.backgroundImg = backgroundImg;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (backgroundImg != null) {
            g.drawImage(backgroundImg, 0, 0, this);
        }
    }

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet() || backgroundImg == null) {
            return super.getPreferredSize();
        } else {
            int w = backgroundImg.getWidth(this);
            int h = backgroundImg.getHeight(this);
            return new Dimension(w, h);
        }
    }
}

@SuppressWarnings("serial")
class GamePanel2 extends JPanel {
    public static final int MAX_BUTTONS = 100;
    private static final int IMG_WIDTH = 40;
    JButton[] gameButtons = new JButton[MAX_BUTTONS];

    public GamePanel2(Image buttonImg) {
        setOpaque(false);
        if (buttonImg.getWidth(this) > IMG_WIDTH) {
            buttonImg = buttonImg.getScaledInstance(IMG_WIDTH, IMG_WIDTH, Image.SCALE_SMOOTH);
        }
        Icon icon = new ImageIcon(buttonImg);
        setLayout(new GridLayout(10, 10, 4, 4));
        for (int i = 0; i < gameButtons.length; i++) {
            int finalIndex = i;
            JButton btn = new JButton(icon);
            btn.addActionListener(e -> {
                String text = String.format("Button: %02d", finalIndex);
                System.out.println(text);
            });
            add(btn);
            gameButtons[i] = btn;            
        }
    }
}

【讨论】:

  • 如果我删除它,背景图像不会覆盖网格上的按钮,但按钮仍然隐藏
  • @paulschmitz82:仍然认为您的空布局有问题。摆脱它,正确使用布局,看看会发生什么。
  • 非常感谢,现在可以了,但是如何消除按钮之间的间隙?
  • 是否可以更改网格布局的大小?
猜你喜欢
  • 2021-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-04
相关资源
最近更新 更多