简体   繁体   English

为什么 repaint() 方法不调用我的 paintComponent() 方法?

[英]Why is the repaint() method not calling my paintComponent() method?

I was trying to copy a repaint() and a paintComponent() method from a tutorial.我试图从教程中复制 repaint() 和 paintComponent() 方法。 After I copied the two methods my paintComponent did not get called and so the rectangle is not being showed.在我复制这两个方法后,我的 paintComponent 没有被调用,所以矩形没有被显示。 Here is my code:这是我的代码:

public class Main {
    GameWindow gw;
    
    Main() {
        gw = new GameWindow();
    }
    
    void start() {
        gw.setWindow();
    }

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

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class GameWindow extends JPanel implements Runnable {
    final int ORIGINAL_TILE_SIZE = 16;
    final int SCALE = 3;
    final int TILE_SIZE = ORIGINAL_TILE_SIZE * SCALE;

    final int MAX_SCREEN_COLUMNS = 16;
    final int MAX_SCREEN_ROWS = 12;
    final int SCREEN_WIDTH = TILE_SIZE * MAX_SCREEN_COLUMNS;
    final int SCREEN_HEIGHT = TILE_SIZE * MAX_SCREEN_ROWS;

    Thread animation;

    void setWindow() {
        JFrame window = new JFrame();

        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setResizable(false);

        window.setTitle("Avontuur");
        window.setPreferredSize(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT));
        window.getContentPane().setBackground(Color.black);

        ImageIcon icon = new ImageIcon("C:\\Users\\Rick\\Desktop\\Star.png");
        window.setIconImage(icon.getImage());
        window.pack();

        window.setLocationRelativeTo(null);
        window.setVisible(true);

        startAnimation();
    }

    void startAnimation() {
        animation = new Thread(this);
        animation.start();
    }

    @Override
    public void run() {
        while (animation != null) {
            update();

            repaint();
        }
    }
    
    public void update() {
        
    }
    
    public void paintComponent(final Graphics g) {
        
        super.paintComponent(g);
        
        Graphics2D g2 = (Graphics2D)g;
        
        g2.setColor(Color.white);
        g2.fillRect(100, 100, TILE_SIZE, TILE_SIZE);
        g2.dispose();
    }
}

I already tried some solutions from stackOverflow, but they did not work or they were not relevant to my problem.我已经尝试过 stackOverflow 的一些解决方案,但它们没有用,或者与我的问题无关。 Now the code above is what I tried myself using the video, but after using a println in the method I saw it was not getting called.现在上面的代码是我自己使用视频尝试的,但是在方法中使用 println 后我发现它没有被调用。 I expected it to work after watching the tutorial, but it didn't.看完教程后,我希望它能工作,但没有。 Does anyone know how I can fix this?有谁知道我该如何解决这个问题? Thanks in advance!提前致谢!

Swing is single threaded - never block the Event Dispatching Thread with long running or blocking operations Swing 是单线程的 - 永远不会阻塞事件调度线程长时间运行或阻塞操作

Swing is NOT thread safe - never update the UI or any state the UI relies on from outside the context of the Event Dispatching Thread. Swing 不是线程安全的 - 永远不要更新 UI 或 state UI 依赖于事件调度线程上下文之外的任何内容。

See Concurrency in Swing for more details.有关详细信息,请参阅Swing中的并发。

Swing makes use of a passive rendering engine - you don't control the painting process and you need to work within in it's intended design/workflow, see Painting in AWT and Swing and Performing Custom Painting for more details. Swing 使用被动渲染引擎 - 您无法控制绘画过程,您需要在其预期的设计/工作流程中工作,请参阅AWT 中的绘画和 Swing以及执行自定义绘画以获取更多详细信息。

So, what's the solution?那么,解决方案是什么? In it's simplest form, use aSwing Timer , for example...在最简单的形式中,使用Swing Timer ,例如......

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

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 GamePane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class GamePane extends JPanel {
        final int ORIGINAL_TILE_SIZE = 16;
        final int SCALE = 3;
        final int TILE_SIZE = ORIGINAL_TILE_SIZE * SCALE;

        final int MAX_SCREEN_COLUMNS = 16;
        final int MAX_SCREEN_ROWS = 12;
        final int SCREEN_WIDTH = TILE_SIZE * MAX_SCREEN_COLUMNS;
        final int SCREEN_HEIGHT = TILE_SIZE * MAX_SCREEN_ROWS;

        private Timer timer;

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT);
        }

        @Override
        public void addNotify() {
            super.addNotify();
            if (timer != null) {
                timer.stop();
            }

            timer = new Timer(5, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    update();
                }
            });
            timer.start();
        }

        @Override
        public void removeNotify() {
            super.removeNotify();
            if (timer != null) {
                timer.stop();
            }

        }

        public void update() {
            System.out.println("Updatey update");
            repaint();
        }

        public void paintComponent(final Graphics g) {
            super.paintComponent(g);

            System.out.println("Painty paint paint");

            Graphics2D g2 = (Graphics2D) g.create();

            g2.setColor(Color.white);
            g2.fillRect(100, 100, TILE_SIZE, TILE_SIZE);
            g2.dispose();
        }
    }
}

You should now see a bunch of text been printed to the console.您现在应该看到一堆文本被打印到控制台。

Also - you might not, I've made some structural changes to your code, there is not reason for a JPanel based class to create it's own window (or if you really wanted to do this, I'd create a static method to do it, but then I'd be questioning why).另外 - 你可能不会,我已经对你的代码进行了一些结构更改,没有理由让基于 class 的JPanel创建它自己的 window(或者如果你真的想这样做,我会创建一个static方法来做它,但后来我会质疑为什么)。

Oh, and also what DontKnowMuchBut Getting Better said in the comments!哦,还有 DontKnowMuchBut Getting Better 在评论中所说的!

Here is the specific rectangle problem with your code, I will not mention other things because is not in the question, you are not adding GameWindow itself as component of your JFrame, and you are not calling your paintComponent method anywhere, I put it on update and it worked fine, but I'm afraid that your code will block and you will not able to move the window and interact with it since you are always calling update/repaint over and over again inside your while statement.这是您的代码的特定矩形问题,我不会提及其他事情,因为不在问题中,您没有将 GameWindow 本身添加为 JFrame 的组件,并且您没有在任何地方调用您的 paintComponent 方法,我把它放在更新中它工作正常,但我担心你的代码会阻塞,你将无法移动 window 并与之交互,因为你总是在你的 while 语句中一遍又一遍地调用更新/重绘。

edit.: As the guy in the comment said, we must not call paintcomponent directly, so I fixed.编辑:正如评论中的那个人所说,我们不能直接调用 paintcomponent,所以我修复了。

void setWindow() {
    JFrame window = new JFrame();

    window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    window.setResizable(false);

    window.setTitle("Avontuur");
    window.add(GameWindow.this);
    window.setPreferredSize(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT));
    window.getContentPane().setBackground(Color.black);

    ImageIcon icon = new ImageIcon("C:\\Users\\Rick\\Desktop\\Star.png");
    window.setIconImage(icon.getImage());
    window.pack();

    window.setLocationRelativeTo(null);
    window.setVisible(true);

    startAnimation();
}

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

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