【问题标题】:Panel not displaying updates after button press按下按钮后面板不显示更新
【发布时间】:2023-01-11 05:17:32
【问题描述】:

我试图让这个 JPanel 在按下一个按钮时显示一个生成的迷宫,并给出它的大小。

我成功地获得了大小,并生成了一个我知道 actionPerformed() 可以访问的迷宫。 单击该按钮时,它让我知道实际上已经创建了一个迷宫,但没有显示它。

我有 paint 方法遍历迷宫数组并填充矩形来显示它。但我不确定它何时被调用或如何手动调用它。 我是 GUI 的新手,所以请理解。

public class View extends JFrame implements ActionListener{

    private static JPanel maze_box;
    private static JLabel message;
    private static JButton generate_button;
    private static JTextField maze_size;
    private static JTextField start_stop;
    private static JButton solve_button;
    private String coords;
    private String size;
    

    private final ArrayList<Integer> path = new ArrayList<Integer>();
    private int[][] maze = {{}};         

    public void paint(Graphics g){
        super.paint(g);
        g.translate(50,50);
        int scale = maze_box.getWidth()/maze.length;
        for(int row=0; row<maze.length; row++){
            for(int col=0; col<maze[0].length; col++){
                System.out.println("drawing");
                Color color;
                switch (maze[row][col]) {
                    case 1 : color = Color.BLACK; break;
                    case 9 : color = Color.RED; break;
                    default : color = Color.WHITE;
                };
                g.setColor(color);
                g.fillRect(10*col, 10*row, 10, 10);
                g.setColor(Color.BLACK);
                g.drawRect(10*col, 10*row, 10, 10);
            }
        }
        for(int p=0; p<path.size(); p+=2){
            System.out.println("drawing");
            int pathX = path.get(p);
            int pathY = path.get(p+1);
            g.setColor(Color.GREEN);
            g.fillRect(pathX*10, pathY*10, 10,10);
        }
        super.paint(g);
        
    }

    public static void main(String[] args){

        JPanel panel = new JPanel();
        JFrame frame = new JFrame();
        frame.setSize(800,800);
        frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
        frame.add(panel);
        frame.setVisible(true);
        panel.setLayout(null);

        maze_box = new JPanel();
        maze_box.setBounds(100, 20, 600, 400);
        maze_box.setBackground(Color.GRAY);
        panel.add(maze_box);

        message = new JLabel();
        message.setBounds(200, 400, 200, 30);
        panel.add(message);

        maze_size = new JTextField("size");
        maze_size.setBounds(200, 550, 100, 30);
        panel.add(maze_size);

        generate_button = new JButton("Generate Maze");
        generate_button.setBounds(500, 550, 100, 30);
        panel.add(generate_button);
        generate_button.addActionListener( new View());

        start_stop = new JTextField("coords");
        start_stop.setBounds(200, 600, 100, 30);
        panel.add(start_stop);

        solve_button = new JButton("Solve!");
        solve_button.setBounds(500, 600, 100, 30);
        panel.add(solve_button);
        solve_button.addActionListener(new View());
    }


    @Override
    public void actionPerformed( ActionEvent aActionEvent ) {
        if ( aActionEvent.getSource() == generate_button ){
            this.size = maze_size.getText();
            try{
                int sized = Integer.parseInt(this.size);
                if(sized>199){
                    message.setText("Please choose a smaller width");
                }if(sized<=0 || this.size.equals("")){
                    message.setText("Please enter valid numbers");
                }else{
                    System.out.println("generating: ");
                    this.maze = new Generate(sized,sized).maze;
                    System.out.println("done "+ this.maze[0][2]);
                }
            }catch(NumberFormatException e){
                
                message.setText("Please enter valid numbers");
            }
        }
    }     
}

这是一个想法的图片。

【问题讨论】:

  • 生成迷宫后尝试添加repaint()。甚至在你尝试之前,尝试调整你的框架大小,看看它是否出现(我认为应该)
  • 在我调整窗口大小之前,“坐标”和“解决”按钮不会出现。但是 repaint() 什么也没做,框仍然是空白的。
  • 你为什么两次打电话给super.paint?事实上,你为什么要覆盖paint(尤其是顶级容器),这是一个问题的根源。 generate_button.addActionListener(new View()); <- 创建 View 的新实例也是一个坏主意

标签: java swing paint


【解决方案1】:

好的,所以你有一系列的问题......

首先,您创建一个JFrame,使其可见,然后将所有组件添加到其中...

JPanel panel = new JPanel();
JFrame frame = new JFrame();
frame.setSize(800, 800);
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.add(panel);
frame.setVisible(true);

...

panel.add(maze_box);
...
panel.add(message);
...
panel.add(maze_size);
...
panel.add(generate_button);
...
panel.add(start_stop);
...
panel.add(solve_button);

Swing 是惰性的,它不会在更新后立即更新 UI。您可以在末尾添加 panel.repaint(),但更简单的解决方案是将 frame.setVisible(true); 调用移动到 main 方法的末尾。

static 的过度使用清楚地表明存在设计问题,您应该学会在没有它的情况下生活(它有它的用途,这不是其中之一)。

这个...

solve_button.addActionListener(new View());

是个坏主意,过度使用 static 也无济于事。您应该只创建一个 View 实例(在此上下文中)并使用它。

作为一般建议,这是一个糟糕的起点......

 public class View extends JFrame implements ActionListener{

您应该避免从顶级容器扩展,它们是复杂的复合容器,并且您不会向该类添加任何新功能。

这会导致覆盖顶级容器的 paint,应该避免这种情况。

如前所述,像JFrame这样的顶级容器是复杂的复合容器,也就是说,它们已经添加了许多子组件,例如......

当像这样重写 paint 时,你会干扰子组件的绘制,更糟的是,因为可以在不调用父组件 paint 工作流的情况下绘制子组件,你最终可能会得到你正在绘制的内容超过。

查看Painting in AWT and SwingPerforming Custom Painting 了解有关绘画如何工作以及您应该如何使用它的更多详细信息(总结是,从JPanel 开始并覆盖paintComponent

但是,你为什么两次打电话给super.paint

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

请注意,View 本身实际上从未在屏幕上显示过,所以无论如何我都会迷路

我还建议您花一些时间回顾一下:

如果我正在做这样的事情,我会专注于 UI 的各个区域并尝试将它们分解为更小的工作单元并隔离它们的功能,也许更像是......

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class Main {
    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new MainPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class MainPane extends JPanel {

        private JLabel message;
        private JTextField mazeSize;
        private JButton generateButton;
        private JTextField startStop;
        private JButton solveButton;

        private MazePane mazePane;

        public MainPane() {
            setLayout(new BorderLayout());

            mazePane = new MazePane();

            add(mazePane);

            JPanel inputPane = new JPanel(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.fill = gbc.HORIZONTAL;
            gbc.insets = new Insets(4, 4, 4, 4);

            message = new JLabel("Make your selections");
            inputPane.add(message, gbc);

            gbc.gridy++;
            mazeSize = new JTextField("size");
            inputPane.add(mazeSize, gbc);

            gbc.gridx++;
            generateButton = new JButton("Generate Maze");
            inputPane.add(generateButton, gbc);
            generateButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    generateMaze();
                }
            });

            gbc.gridx = 0;
            gbc.gridy++;
            startStop = new JTextField("coords");
            inputPane.add(startStop, gbc);

            gbc.gridx++;
            solveButton = new JButton("Solve!");
            inputPane.add(solveButton, gbc);

            add(inputPane, BorderLayout.SOUTH);
        }

        protected void generateMaze() {
            String size = mazeSize.getText();
            try {
                int sized = Integer.parseInt(size);
                if (sized > 199) {
                    message.setText("Please choose a smaller width");
                } else if (sized <= 0) {
                    message.setText("Please enter valid numbers");
                } else {
                    //System.out.println("generating: ");
                    //int[][] maze = new Generate(sized, sized).maze;
                    //System.out.println("done " + this.maze[0][2]);
                    // Replace with maze
                    mazePane.setMaze(new int[][] {{}});
                }
                revalidate();
                repaint();
            } catch (NumberFormatException e) {
                message.setText("Please enter valid numbers");
            }
        }
    }

    public class MazePane extends JPanel {

        private int[][] maze = {{}};
        private final ArrayList<Integer> path = new ArrayList<Integer>();

        public MazePane() {
            setBackground(Color.GRAY);
        }

        public void setMaze(int[][] maze) {
            this.maze = maze;
            repaint();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(800, 600);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.translate(50, 50);
            int scale = getWidth() / maze.length;
            for (int row = 0; row < maze.length; row++) {
                for (int col = 0; col < maze[0].length; col++) {
                    System.out.println("drawing");
                    Color color;
                    switch (maze[row][col]) {
                        case 1:
                            color = Color.BLACK;
                            break;
                        case 9:
                            color = Color.RED;
                            break;
                        default:
                            color = Color.WHITE;
                    }
                    g2d.setColor(color);
                    g2d.fillRect(10 * col, 10 * row, 10, 10);
                    g2d.setColor(Color.BLACK);
                    g2d.drawRect(10 * col, 10 * row, 10, 10);
                }
            }
            for (int p = 0; p < path.size(); p += 2) {
                System.out.println("drawing");
                int pathX = path.get(p);
                int pathY = path.get(p + 1);
                g2d.setColor(Color.GREEN);
                g2d.fillRect(pathX * 10, pathY * 10, 10, 10);
            }
            g2d.dispose();
        }

    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-05
    • 2017-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多