繁体   English   中英

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

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

我试图从教程中复制 repaint() 和 paintComponent() 方法。 在我复制这两个方法后,我的 paintComponent 没有被调用,所以矩形没有被显示。 这是我的代码:

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();
    }
}

我已经尝试过 stackOverflow 的一些解决方案,但它们没有用,或者与我的问题无关。 现在上面的代码是我自己使用视频尝试的,但是在方法中使用 println 后我发现它没有被调用。 看完教程后,我希望它能工作,但没有。 有谁知道我该如何解决这个问题? 提前致谢!

Swing 是单线程的 - 永远不会阻塞事件调度线程长时间运行或阻塞操作

Swing 不是线程安全的 - 永远不要更新 UI 或 state UI 依赖于事件调度线程上下文之外的任何内容。

有关详细信息,请参阅Swing中的并发。

Swing 使用被动渲染引擎 - 您无法控制绘画过程,您需要在其预期的设计/工作流程中工作,请参阅AWT 中的绘画和 Swing以及执行自定义绘画以获取更多详细信息。

那么,解决方案是什么? 在最简单的形式中,使用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();
        }
    }
}

您现在应该看到一堆文本被打印到控制台。

另外 - 你可能不会,我已经对你的代码进行了一些结构更改,没有理由让基于 class 的JPanel创建它自己的 window(或者如果你真的想这样做,我会创建一个static方法来做它,但后来我会质疑为什么)。

哦,还有 DontKnowMuchBut Getting Better 在评论中所说的!

这是您的代码的特定矩形问题,我不会提及其他事情,因为不在问题中,您没有将 GameWindow 本身添加为 JFrame 的组件,并且您没有在任何地方调用您的 paintComponent 方法,我把它放在更新中它工作正常,但我担心你的代码会阻塞,你将无法移动 window 并与之交互,因为你总是在你的 while 语句中一遍又一遍地调用更新/重绘。

编辑:正如评论中的那个人所说,我们不能直接调用 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