永远不会调用paintComponent()

Posted

技术标签:

【中文标题】永远不会调用paintComponent()【英文标题】:paintComponent() Is Never Called 【发布时间】:2021-04-15 23:05:24 【问题描述】:

在完善我的程序的过程中,我不可避免地打破了一些东西。以前,我的迷宫画得很漂亮,但现在从不调用 paintComponent()(根据 sys-out 调试文本)。我已经让其他元素可以很好地改变可见性,但是当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);
    

迷宫.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
    ;

【问题讨论】:

在这种情况下使用static 将为MazePanel 的每个实例呈现相同的迷宫数据 每次更改组件树时都要记住repaint 和revalidate。在这种情况下,您可以在所有这些 ActionListener 中执行此操作。 我也会考虑看看CardLayout JFrame 默认使用BorderLayout,这只会管理/布局添加到每个可用位置的最后一个组件 - 因此,这意味着,实际布局的唯一组件是面板包含startp,所有其他组件都保留在原始大小 0x0 并且 Swing 足够聪明,不会绘制没有大小的组件 【参考方案1】:

JFrame 默认使用BorderLayout,这只会管理/布局添加到每个可用位置的最后一个组件 - 因此,这意味着,实际布局的唯一组件是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 的每个实例都将具有相同的数据

【讨论】:

以上是关于永远不会调用paintComponent()的主要内容,如果未能解决你的问题,请参考以下文章

Java - 方法 repaint() 不调用 paintComponent() 方法

java中的paintComponent啥时候被调用

Objective-C 完成调用永远不会完成

IOS:UITextInput 上的 Tokenizer 永远不会被调用

S3.putObject - 回调永远不会被调用

Android onSystemUiVisibilityChange 永远不会被调用