paintComponent() 从未被调用

paintComponent() Is Never Called

在完善我的程序的过程中,我不可避免地破坏了一些东西。以前,我的迷宫画得很漂亮,但现在根本没有调用 paintComponent()(根据系统输出调试文本)。我有其他元素可以很好地改变可见性,但是当 mazep 设置为可见时,它们从不绘制。任何帮助将不胜感激 - 我可能只是盯着它看了太久才发现问题所在。

GUI.java

package com.whatever;

import javax.swing.*;

import com.whatever.models.Maze;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class GUI extends JFrame {
    private static final long serialVersionUID = 1L;
    
    public GUI() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(1000, 500);
        
        JPanel startp = new JPanel();
        
        MazePanel mazep1 = new MazePanel();
        mazep1.setMaze(Maze.Maze1);
        add(mazep1);
        mazep1.setVisible(true);
        
        MazePanel mazep2 = new MazePanel();
        mazep2.setMaze(Maze.Maze2);
        add(mazep2, BorderLayout.CENTER);
        mazep2.setVisible(false);
        
        MazePanel mazep3 = new MazePanel();
        mazep3.setMaze(Maze.Maze3);
        add(mazep3, BorderLayout.CENTER);
        mazep3.setVisible(false);
        
        JMenuBar menuBar = new JMenuBar();  
        JMenuItem reset = new JMenuItem("Reset");
        JMenuItem back = new JMenuItem("Return");
        
        menuBar.add(reset);
        reset.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                System.out.println("Reset has been pushed!");
                mazep1.setMaze(Maze.Maze1);
                mazep2.setMaze(Maze.Maze2);
                mazep3.setMaze(Maze.Maze3);
            }
        });
        menuBar.add(Box.createHorizontalGlue());
        menuBar.add(back);
        back.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                System.out.println("Back to the main screen!");
                menuBar.setVisible(false);
                startp.setVisible(true);
                mazep1.setVisible(false);
                mazep2.setVisible(false);
                mazep3.setVisible(false);
            }
        });
        setJMenuBar(menuBar);
        menuBar.setVisible(false);

        startp.setLayout(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();
        Label title = new Label("Heaven & Earth");
        title.setAlignment(Label.CENTER);
        c.gridx = 0;
        c.gridy = 0;
        startp.add(title, c);
        JButton easy = new JButton("Easy");
        c.gridy = 1;
        startp.add(easy, c);
        easy.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                System.out.println("To the easy maze!");
                menuBar.setVisible(true);
                mazep1.setVisible(true);
                startp.setVisible(false);
                mazep2.setVisible(false);
                mazep3.setVisible(false);
            }
        });
        JButton medium = new JButton("Medium");
        c.gridy = 2;
        startp.add(medium, c);
        medium.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                System.out.println("To the medium maze!");
                menuBar.setVisible(true);
                mazep2.setVisible(true);
                startp.setVisible(false);
                mazep1.setVisible(false);
                mazep3.setVisible(false);
            }
        });
        JButton hard = new JButton("Hard");
        c.gridy = 3;
        startp.add(hard, c);
        hard.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                System.out.println("To the hard maze!");
                menuBar.setVisible(true);
                mazep3.setVisible(true);
                startp.setVisible(false);
                mazep1.setVisible(false);
                mazep2.setVisible(false);
            }
        });
        startp.setVisible(true);        
        add(startp);
        
        setVisible(true);
    }
}

class MazePanel extends JPanel {
    private static final long serialVersionUID = 1L;
    private static char[][] maze = null;
    private static int x1, y1, x2, y2 = 0;
    
    public void setMaze(char[][] maze) {
        String type = null;
        if (maze.equals(Maze.Maze1)) {
            type = "easy";
        } else if (maze.equals(Maze.Maze2)) {
            type = "medium";
        } else if (maze.equals(Maze.Maze3)) {
            type = "hard";
        }
        
        System.out.println("I've set the " + type + " maze!");
        this.maze = maze;
        boolean first = true;
        for(int i = 0; i < maze.length; i++) {
            for(int j = 0; j < maze[i].length; j++) {
                if(maze[i][j] == 's' && first) {
                    x1 = j;
                    y1 = i;
                    first = false;
                } else if(maze[i][j] == 's' && !first) {
                    x2 = j;
                    y2 = i;
                }
                if (maze[i][j] == 0) {
                }
                //System.out.print(maze[i][j] + " ");
            }
            //System.out.println();
        }
    }
    
    @Override
    public Dimension getPreferredSize() {
        return new Dimension(1000, 500);
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        System.out.println("Painting now!");
        final int HOROFF = 250;
        final int VEROFF = 50; 
        for(int i = 0; i < maze.length; i++) {
            for(int j = 0; j < maze[i].length; j++) {
                if(maze[i][j] == 1) {
                    g.setColor(Color.BLACK);
                    g.fillRect(j * 25 + HOROFF, i * 25 + VEROFF, 25, 25);
                } else if((i == y1 && j == x1) || (i == y2 && j == x2)) {
                    g.setColor(Color.BLUE);
                    g.fillRect(j * 25 + HOROFF, i * 25 + VEROFF, 25, 25);
                } else if(maze[i][j] == 'e') {
                    g.setColor(Color.WHITE);
                    g.fillRect(j * 25 + HOROFF, i * 25 + VEROFF, 25, 25);
                }
            }
        }
        g.setColor(Color.BLACK);
        g.drawRect(HOROFF, VEROFF, maze[0].length * 25, maze.length * 25);
    }
}

Maze.java


import java.awt.Panel;

public class Maze extends Panel {
    
    private static final long serialVersionUID = 1L;
    
    public static char[][] Maze1 = {
            {0,0,0,0,0,0,0,'e',1,0,1,0,0,0,0,0,'e'},
            {0,1,0,1,1,1,1,0,1,0,1,0,1,1,1,1,1},
            {0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0},
            {0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0},
            {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0},
            {0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1},
            {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0},
            {0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0},
            {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0},
            {0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0},
            {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0},
            {1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0},
            {'s',0,0,0,0,0,0,0,1,'s',0,0,0,0,0,0,0}
    };
    
    public static char[][] Maze2 = {
            {0,0,0,0,0,0,0,0,1,'e',1,0,0,0,0,0,0,0,0,0,'e'},
            {0,0,0,1,0,0,0,1,0,0,1,0,1,1,0,0,0,1,0,1,0},
            {0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0},
            {0,1,0,0,0,1,0,1,0,1,1,1,0,0,0,0,0,1,0,1,0},
            {0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0},
            {0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0},
            {0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0},
            {1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0},
            {0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,0},
            {0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0},
            {'s',0,0,0,0,0,0,0,0,1,1,'s',0,0,1,0,0,0,0,0,0}
    };

    public static char[][] Maze3 = {
            {0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0},
            {0,1,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0},
            {0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0},
            {0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0},
            {1,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0},
            {1,0,0,1,0,0,0,1,0,'s',1,'s',1,0,0,0,0,1,1,0,1,0},
            {0,0,0,0,0,1,0,0,0,1,'e',0,'e',1,0,0,0,0,0,0,0,1},
            {0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0},
            {0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0},
            {1,0,0,1,0,0,0,1,0,0,0,0,1,0,1,0,0,1,0,0,0,0},
            {0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0},
            {1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0}
    };
}

JFrame 默认使用 BorderLayout,这只会 manage/layout 添加到每个可用位置的最后一个组件 - 因此,这意味着实际布局的唯一组件是 startp 面板,所有其他组件都保留原始大小 0x0,Swing 足够聪明,不会绘制没有大小的组件。

更好的解决方案是使用 CardLayout 旨在完全按照您的意愿进行设计。

例如...

import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Label;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;

public class GUI extends JFrame {

    private static final long serialVersionUID = 1L;

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new GUI();
                frame.pack();
                frame.setLocationByPlatform(true);
                frame.setVisible(true);
            }
        });
    }

    private CardLayout cardLayout = new CardLayout();

    public GUI() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(1000, 500);


        setLayout(cardLayout);

        JPanel startp = new JPanel();

        MazePanel mazep1 = new MazePanel();
        mazep1.setMaze(Maze.Maze1);
        add(mazep1, "easyMaze");

        MazePanel mazep2 = new MazePanel();
        mazep2.setMaze(Maze.Maze2);
        add(mazep2, "medMaze");

        MazePanel mazep3 = new MazePanel();
        mazep3.setMaze(Maze.Maze3);
        add(mazep3, "hardMaze");

        JMenuBar menuBar = new JMenuBar();
        JMenuItem reset = new JMenuItem("Reset");
        JMenuItem back = new JMenuItem("Return");

        menuBar.add(reset);
        reset.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                System.out.println("Reset has been pushed!");
                mazep1.setMaze(Maze.Maze1);
                mazep2.setMaze(Maze.Maze2);
                mazep3.setMaze(Maze.Maze3);
            }
        });
        menuBar.add(Box.createHorizontalGlue());
        menuBar.add(back);
        back.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                System.out.println("Back to the main screen!");
                cardLayout.show(getContentPane(), "startup");
                menuBar.setVisible(false);
            }
        });
        setJMenuBar(menuBar);
        menuBar.setVisible(false);

        startp.setLayout(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();
        Label title = new Label("Heaven & Earth");
        title.setAlignment(Label.CENTER);
        c.gridx = 0;
        c.gridy = 0;
        startp.add(title, c);
        JButton easy = new JButton("Easy");
        c.gridy = 1;
        startp.add(easy, c);
        easy.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                System.out.println("To the easy maze!");
                menuBar.setVisible(true);
                cardLayout.show(getContentPane(), "easyMaze");
            }
        });
        JButton medium = new JButton("Medium");
        c.gridy = 2;
        startp.add(medium, c);
        medium.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                System.out.println("To the medium maze!");
                cardLayout.show(getContentPane(), "medMaze");
                menuBar.setVisible(true);
            }
        });
        JButton hard = new JButton("Hard");
        c.gridy = 3;
        startp.add(hard, c);
        hard.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                System.out.println("To the hard maze!");
                cardLayout.show(getContentPane(), "hardMaze");
                menuBar.setVisible(true);
            }
        });
        add(startp, "startup");

        cardLayout.show(getContentPane(), "startup");

        //setVisible(true);
    }

    static class MazePanel extends JPanel {

        private final long serialVersionUID = 1L;
        private char[][] maze = null;
        private int x1, y1, x2, y2 = 0;

        public void setMaze(char[][] maze) {
            String type = null;
            if (maze.equals(Maze.Maze1)) {
                type = "easy";
            } else if (maze.equals(Maze.Maze2)) {
                type = "medium";
            } else if (maze.equals(Maze.Maze3)) {
                type = "hard";
            }

            System.out.println("I've set the " + type + " maze!");
            this.maze = maze;
            boolean first = true;
            for (int i = 0; i < maze.length; i++) {
                for (int j = 0; j < maze[i].length; j++) {
                    if (maze[i][j] == 's' && first) {
                        x1 = j;
                        y1 = i;
                        first = false;
                    } else if (maze[i][j] == 's' && !first) {
                        x2 = j;
                        y2 = i;
                    }
                    if (maze[i][j] == 0) {
                    }
                    //System.out.print(maze[i][j] + " ");
                }
                //System.out.println();
            }
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(1000, 500);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            System.out.println("Painting now!");
            final int HOROFF = 250;
            final int VEROFF = 50;
            for (int i = 0; i < maze.length; i++) {
                for (int j = 0; j < maze[i].length; j++) {
                    if (maze[i][j] == 1) {
                        g.setColor(Color.BLACK);
                        g.fillRect(j * 25 + HOROFF, i * 25 + VEROFF, 25, 25);
                    } else if ((i == y1 && j == x1) || (i == y2 && j == x2)) {
                        g.setColor(Color.BLUE);
                        g.fillRect(j * 25 + HOROFF, i * 25 + VEROFF, 25, 25);
                    } else if (maze[i][j] == 'e') {
                        g.setColor(Color.WHITE);
                        g.fillRect(j * 25 + HOROFF, i * 25 + VEROFF, 25, 25);
                    }
                }
            }
            g.setColor(Color.BLACK);
            g.drawRect(HOROFF, VEROFF, maze[0].length * 25, maze.length * 25);
        }
    }

    public static class Maze {

        private static final long serialVersionUID = 1L;

        public static char[][] Maze1 = {
            {0, 0, 0, 0, 0, 0, 0, 'e', 1, 0, 1, 0, 0, 0, 0, 0, 'e'},
            {0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1},
            {0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1},
            {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0},
            {0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
            {1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0},
            {'s', 0, 0, 0, 0, 0, 0, 0, 1, 's', 0, 0, 0, 0, 0, 0, 0}
        };

        public static char[][] Maze2 = {
            {0, 0, 0, 0, 0, 0, 0, 0, 1, 'e', 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'e'},
            {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
            {0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0},
            {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
            {0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0},
            {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0},
            {1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0},
            {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0},
            {0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {'s', 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 's', 0, 0, 1, 0, 0, 0, 0, 0, 0}
        };

        public static char[][] Maze3 = {
            {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
            {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0},
            {0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0},
            {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0},
            {1, 0, 0, 1, 0, 0, 0, 1, 0, 's', 1, 's', 1, 0, 0, 0, 0, 1, 1, 0, 1, 0},
            {0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 'e', 0, 'e', 1, 0, 0, 0, 0, 0, 0, 0, 1},
            {0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0},
            {1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0},
            {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0},
            {1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
        };
    }
}

此外,在 MazePanel 中使用 static 是不可取的,因为这意味着 MazePanel 的每个实例都将具有相同的数据