简体   繁体   English

单击按钮时JButton不会更新

[英]JButtons won't update on button click

Currently displays a GUI with an 8x8 grid of randomized colored buttons. 当前显示带有8x8随机彩色按钮网格的GUI。 The newButton is to reset the score display to 0 and reset the grid with a fresh like it does on startup after being clicked. newButton用于将得分显示重置为0,并像单击后启动时一样重新设置网格。 I haven't been able to find many solutions other than that it's to do with the way Java displays it's buttons and the way layering works. 除了Java与显示按钮的方式以及分层的工作方式有关,我无法找到许多解决方案。 Here are the 2 classes I'm using. 这是我正在使用的2个类。

import javax.swing.JFrame; 
import javax.swing.*;
import java.awt.event.*;
import javax.swing.JPanel;
import java.awt.Color;

public class ShinyButtonsApp extends JFrame implements ActionListener {

    private static byte ROWS = 8;
    public int useThis; 
    ShinyButtons shiny = new ShinyButtons();
    public static ImageIcon[] icons = {new ImageIcon("RedButton.png"),
                                       new ImageIcon("OrangeButton.png"), 
                                       new ImageIcon("YellowButton.png"), 
                                       new ImageIcon("GreenButton.png"), 
                                       new ImageIcon("BlueButton.png"), 
                                       new ImageIcon("LightGrayButton.png"), 
                                       new ImageIcon("DarkGrayButton.png")}; 


    public ShinyButtonsApp(String title) { 
        super(title); // Set title of window 
        setDefaultCloseOperation(EXIT_ON_CLOSE); // allow window to close 
        setSize(578, 634); // Set size of window 
        setResizable(false);

        getContentPane().setLayout(null);   

        JLabel aLabel = new JLabel("Score: "); 
        aLabel.setLocation(10, 570); 
        aLabel.setSize(80,30); 
        getContentPane().add(aLabel);

        JTextField scoreField = new JTextField(); 
        scoreField.setText(Integer.toString(shiny.score));
        scoreField.setEditable(false);
        scoreField.setHorizontalAlignment(JTextField.RIGHT);
        scoreField.setLocation(60, 570); 
        scoreField.setSize(120,30);
        scoreField.setBackground(Color.WHITE); 
        getContentPane().add(scoreField);

        JButton newButton = new JButton("New Game");
        newButton.addActionListener(this);
        newButton.setLocation(348,570);
        newButton.setSize(110,30);
        getContentPane().add(newButton);

        JButton quitButton = new JButton("Quit");
        quitButton.setLocation(468,570);
        quitButton.setSize(80,30);
        getContentPane().add(quitButton);

        resetButtons2();
    } 

    public void actionPerformed(ActionEvent e) {
                shiny.score = 0;
                shiny.resetButtons();
                resetButtons2();
    }

    public void resetButtons2() {
        for (int r=0; r<ROWS; r++) {
            for (int c=0; c<ROWS; c++) {
                ImageIcon image1 = icons[(int)shiny.getButton(r,c)];
                JButton button = new JButton(image1);
                button.setLocation(10+(69*r),10+(69*c));
                button.setSize(69,69);
                button.setBorder(BorderFactory.createLineBorder(Color.GRAY,1));
                getContentPane().add(button);
            }
        }
    }

    public static void main(String[] args) { 
        ShinyButtonsApp frame;      
        frame = new ShinyButtonsApp("Shiny Buttons"); // Create window 
        frame.setVisible(true); // Show window      
    }   
}

and

import javax.swing.JFrame; 
import javax.swing.*;
import java.awt.event.*;
import javax.swing.JPanel;
import java.awt.Color;

public class ShinyButtons extends JPanel{ 
    public static byte RED = 0; 
    public static byte ORANGE = 1; 
    public static byte YELLOW = 2; 
    public static byte GREEN = 3; 
    public static byte BLUE = 4; 
    public static byte LIGHT_GRAY = 5; 
    public static byte DARK_GRAY = 6; 

    public static byte ROWS = 8; 

    public byte[][] buttonTable;

    public int score = 0; 

    public ShinyButtons() { 
        buttonTable = new byte[ROWS][ROWS]; 
        resetButtons(); 
    } 

    public void resetButtons() { 
        for (int r=0; r<ROWS; r++) 
            for (int c=0; c<ROWS; c++) 
                buttonTable[r][c] = (byte)(Math.random()*7); 
    } 

    public byte getButton(int r, int c) { return buttonTable[r][c]; } 

    public int getScore() { return score; }
} 

You are creating a new set of buttons in resetButtons2() and placing them on top (or rather under) of the already existing set of buttons in the same locations. 您将在resetButtons2()中创建一组新的按钮,并将它们放置在相同位置的现有按钮组的顶部(或下面)。 You should create the set of buttons once and only update their icons upon reset. 您应该创建一次按钮组,并且仅在重置后更新它们的图标。

You should do a number of things: 您应该做一些事情:

  • Use a proper layout manager, eg, GridLayout 使用适当的布局管理器,例如GridLayout
  • Create the 8x8 grid of buttons only once and replace their icons when needed 仅创建一次8x8的按钮网格,并在需要时替换其图标
  • Call invalidate/repaint to refresh the content pane 调用无效/重新绘制以刷新内容窗格

And for a JFrame you don't need getContentPane().add(...) , you can directly do add(...) 对于JFrame您不需要getContentPane().add(...) ,您可以直接执行add(...)

Two things. 两件事情。

First, make sure you remove the existing buttons first. 首先,请确保先删除现有按钮。 Alternatively, you could simply update the state of the buttons. 或者,您可以简单地更新按钮的状态。 This would require you to create an array or List of buttons first, which your reset method would then iterate over and update their properties as required. 这将需要您首先创建一个数组或按钮List ,然后您的reset方法将对其进行迭代并根据需要更新其属性。

Second, make use of an appropriate layout manager. 其次,使用适当的布局管理器。 A null layout ias a very bad idea. null布局是一个非常糟糕的主意。 You do not control the font metrics of the underlying platform and this will change how your buttons look on different systems, making your UI less dynamic then it should be 您不控制基础平台的字体指标,这将改变按钮在不同系统上的外观,使用户界面的动态性降低

Building on to what this answer points out (using layout managers instead of setting size, as you should be doing) you could reset the the images just by looping through the components ( JLabels ) of the JPanel and changing their icons. 建立在什么这个答案指出(使用布局管理器,而不是设置大小,你应该做的),你可以只通过该组件(循环的图像复位JLabels )的中JPanel并改变它们的图标。

This particular example uses JLabels with MouseListeners but it could easily be switched to JButtons with ActionListeners 这个特定的示例将JLabelsMouseListeners一起使用,但可以轻松将其与ActionListeners切换为JButtons

newGame.addActionListener(new ActionListener(){
    public void actionPerformed(ActionEvent e) {
         reset(iconPanel, icons);               <--- call reset method from below
         score = 0;
         scoreField.setText(String.valueOf(score));
    }
});
....

private void reset(JPanel panel, ImageIcon[] icons) {
    Component[] comps = panel.getComponents();
    Random random = new Random();
    for(Component c : comps) {
        if (c instanceof JLabel) {
            JLabel button = (JLabel)c;
            int index = random.nextInt(icons.length);
            button.setIcon(icons[index]);
        }
    }
}

在此处输入图片说明

Here's the complete running code. 这是完整的运行代码。 You just need to replace the image paths. 您只需要替换图像路径。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;

public class CircleImages {

    private int score = 0;
    private JTextField scoreField = new JTextField(10);

    public CircleImages() {
        scoreField.setEditable(false);

        final ImageIcon[] icons = createImageIcons();
        final JPanel iconPanel = createPanel(icons, 8);

        JPanel bottomLeftPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
        bottomLeftPanel.add(new JLabel("Score: "));
        bottomLeftPanel.add(scoreField);

        JPanel bottomRightPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING));
        JButton newGame = new JButton("New Game");
        bottomRightPanel.add(newGame);
        JButton quit = new JButton("Quit");
        bottomRightPanel.add(quit);

        JPanel bottomPanel = new JPanel(new GridLayout(1, 2));
        bottomPanel.add(bottomLeftPanel);
        bottomPanel.add(bottomRightPanel);

        newGame.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e) {
                reset(iconPanel, icons);
                score = 0;
                scoreField.setText(String.valueOf(score));
            }
        });

        JFrame frame = new JFrame();
        frame.add(iconPanel);
        frame.add(bottomPanel, BorderLayout.PAGE_END);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private void reset(JPanel panel, ImageIcon[] icons) {
        Component[] comps = panel.getComponents();
        Random random = new Random();
        for(Component c : comps) {
            if (c instanceof JLabel) {
                JLabel button = (JLabel)c;
                int index = random.nextInt(icons.length);
                button.setIcon(icons[index]);
            }
        }
    }

    private JPanel createPanel(ImageIcon[] icons, int gridSize) {
        Random random = new Random();
        JPanel panel = new JPanel(new GridLayout(gridSize, gridSize));
        for (int i = 0; i < gridSize * gridSize; i++) {
            int index = random.nextInt(icons.length);
            JLabel label = new JLabel(icons[index]);
            label.addMouseListener(new MouseAdapter(){
                public void mouseClicked(MouseEvent e) {
                    score += 1;
                    scoreField.setText(String.valueOf(score));
                }
            });
            label.setBorder(new LineBorder(Color.GRAY, 2));
            panel.add(label);
        }
        return panel;
    }

    private ImageIcon[] createImageIcons() {
        String[] files = {"blackcircle.png",
            "bluecircle.png",
            "greencircle.png",
            "greycircle.png",
            "orangecircle.png",
            "redcircle.png",
            "yellowcircle.png"
        };
        ImageIcon[] icons = new ImageIcon[files.length];
        for (int i = 0; i < files.length; i++) {
            icons[i] = new ImageIcon(getClass().getResource("/circles/" + files[i]));
        }
        return icons;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new CircleImages();
            }
        });
    }
}

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

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