一旦 JComponent 离开屏幕,它就会停止渲染 [英] JComponent stops getting rendered once it goes off the screen

查看:26
本文介绍了一旦 JComponent 离开屏幕,它就会停止渲染的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试制作一个简单的动画,其中一个矩形从屏幕开始(在屏幕右边缘的右侧)并向左移动.因此,在这种情况下,我的框架的宽度为 1000,而墙从 x 值为 1100 开始.显然,起初,矩形不应该是对我们可见.但是随着矩形向左移动,它最终应该变得可见.然而,这个动画并没有这样做.即使墙的 x 值在屏幕范围内,它也不会被渲染.

我尝试在墙的paintComponent()方法中放入println()语句,发现paintComponent()没有被框架的 repaint() 方法调用.我认为当墙第一次被添加到框架时,Swing 决定因为它不在屏幕上,所以不需要渲染,所以即使墙最终出现在屏幕上,Swing 认为它不需要得到渲染.

我尝试重新验证和使框架和组件无效,但没有任何效果.请帮我解决这个问题.代码如下:

package graphics.simpleAnimation;公共类 Simple_Animation 实现 Runnable {私人用户界面 ui;//用户界面(框架)私人墙墙;//在屏幕上移动的墙对象私人 Simple_Animation() {//初始化墙对象(故意给定一个大于框架宽度的 x 值)墙 = 新墙(1100, 400, 200, 400);//初始化UI(宽度只有1000)ui = new UI(1000, 600, "几何破折号");//将墙添加到 ui(框架)ui.add(墙);}公共无效运行(){//设置框架可见ui.setVisible(true);//重新绘制框架并移动墙壁而(真){ui.repaint();wall.moveWall(-2, 0);尝试 {线程睡眠(16);} catch (InterruptedException IE) {System.out.println(IE);}}}//在新线程中启动程序公共静态无效主(字符串 [] args){Simple_Animation simpleAnimation = new Simple_Animation();新线程(简单动画).开始();}}包 graphics.simpleAnimation;导入 javax.swing.*;导入 java.awt.*;公共类 UI 扩展 JFrame {//存储内容窗格(正在呈现组件的位置)的宽度和高度的变量公共 int content_pane_width;公共 int content_pane_height;公共用户界面(int frameW,int frameH,String frameTitle){setTitle(frameTitle);setSize(frameW, frameH);setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);设置布局(空);content_pane_width = getContentPane().getWidth();content_pane_height = getContentPane().getHeight();}@覆盖公共无效油漆(图形g){super.paint(g);}}包 graphics.simpleAnimation;导入 java.awt.*;导入 javax.swing.*;公共类墙扩展 JComponent {private int wallX;private int wallY;private int wallW;private int wallH;墙(int x,int y,int sizeX,int sizeY){墙X = x;墙Y = y;墙W = 尺寸X;墙H = 大小Y;setSize(getPreferredSize());}公共无效移动墙(int moveX,int moveY){wallX += moveX;wallY += moveY;}@覆盖公共维度 getPreferredSize() {返回新维度(wallW,wallH);}@覆盖公共无效paintComponent(图形g){Graphics2D g2d = (Graphics2D) g;设置位置(wallX,wallY);g2d.fillRect(0, 0, wallW, wallH);}}

解决方案

我可以在你的程序中找到几个错误

  1. 您正在使用 null 布局,请参阅

    I am trying to make a simple animation in which a rectangle starts off the screen (on the right side of the right edge of the screen) and moves towards the left. So, in this case, my frame has a width of 1000 and the wall starts off at an x-value of 1100. Obviously, at first, the rectangle is not supposed to be visible to us. But as the rectangle moves to the left, it should eventually become visible. However, this animation doesn't do that. Even when the wall's x-value is within the bounds of the screen, it isn't being rendered.

    I tried putting a println() statement in the paintComponent() method of the wall, and I discovered that the paintComponent() wasn't getting called by the frame's repaint() method. I figured that when the wall was first added to the frame, Swing decided that since it was off the screen it doesn't need to get rendered, and so even when the wall eventually gets on the screen Swing thinks that it doesn't need to get rendered.

    I have tried revalidating and invalidating the frame and the component, but nothing has worked. Please help me to fix this. Below is the code:

    package graphics.simpleAnimation;
    
    public class Simple_Animation implements Runnable {
    
        private UI ui; // The UI (frame)
    
        private Wall wall; // Wall object that moves across the screen
    
        private Simple_Animation() {
    
            // Initialize the wall object (intentionally given an x value that is greater than the frame's width)
            wall = new Wall(1100, 400, 200, 400);
    
            // Initialize the UI (width is only 1000)
            ui = new UI(1000, 600, "Geometry Dash");
    
            // Add the wall to the ui (the frame)
            ui.add(wall);
    
        }
    
        public void run() {
            // Set the frame visible
            ui.setVisible(true);
    
            // Repaint the frame and move the wall
            while (true) {
                ui.repaint();
                wall.moveWall(-2, 0);
    
                try {
                    Thread.sleep(16);
                } catch (InterruptedException IE) {
                    System.out.println(IE);
                }
    
            }
    
        }
    
        // Starts the program in a new thread
        public static void main(String[] args) {
            Simple_Animation simpleAnimation = new Simple_Animation();
            new Thread(simpleAnimation).start();
        }
    
    }
    
    
    package graphics.simpleAnimation;
    
    import javax.swing.*;
    import java.awt.*;
    
    public class UI extends JFrame {
    
        // Variables storing the width and height of the content pane (where the components are being rendered)
        public int content_pane_width;
        public int content_pane_height;
    
        public UI(int frameW, int frameH, String frameTitle) {
    
            setTitle(frameTitle);
            setSize(frameW, frameH);
            setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            setLayout(null);
    
            content_pane_width = getContentPane().getWidth();
            content_pane_height = getContentPane().getHeight();
    
        }
    
        @Override
        public void paint(Graphics g) {
            super.paint(g);
        }
    
    }
    
    package graphics.simpleAnimation;
    
    import java.awt.*;
    import javax.swing.*;
    
    public class Wall extends JComponent {
    
        private int wallX;
        private int wallY;
        private int wallW;
        private int wallH;
    
    
        Wall(int x, int y, int sizeX, int sizeY) {
            wallX = x;
            wallY = y;
            wallW = sizeX;
            wallH = sizeY;
    
            setSize(getPreferredSize());
        }
    
        public void moveWall(int moveX, int moveY) {
            wallX += moveX;
            wallY += moveY;
        }
    
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(wallW, wallH);
        }
    
        @Override
        public void paintComponent(Graphics g) {
            Graphics2D g2d = (Graphics2D) g;
    
            setLocation(wallX, wallY);
            g2d.fillRect(0, 0, wallW, wallH);
        }
    }
    

    解决方案

    There are a couple of errors I can find in your program

    1. You're using a null layout, please see Null layout is evil and the answers in this question to see why you should avoid its use. (Probably not in this case, as per @MadProgrammer's comment below), this is just another approach

    2. while (true) { this line might block the Event Dispatch Thread (EDT) along with this line: Thread.sleep(16);, See Lesson: Concurrency in Swing to learn more about and How to use Swing Timers. You should also place your program on the EDT which can be done:

      public static void main(String[] args) {
          SwingUtilities.invokeLater(new Runnable() {
              @Override
              public void run() {
                  //Your constructor here
              }
          });
      }
      

    3. You're not calling super.paintComponent() on your paintComponent() method of the Wall class which could break the paint chain, always call it first.

    4. You're extending JComponent, it would be better to extend JPanel and do custom painting over it using the Shapes API

    With all of the above in mind, you can then have a code like this one:

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.geom.Rectangle2D;
    
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    import javax.swing.Timer;
    
    public class SingleAnimation {
    
        private JFrame frame;
        private Timer timer;
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    new SingleAnimation().createAndShowGui();
                }
            });
        }
    
        public void createAndShowGui() {
            frame = new JFrame(getClass().getSimpleName());
    
            Wall wall = new Wall(300, 0);
    
            timer = new Timer(16, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    wall.moveWall(-2, 0);
                }
            });
    
            timer.setInitialDelay(0);
            timer.start();
    
            frame.add(wall);
            frame.pack();
            frame.setVisible(true);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }
    }
    
    class Wall extends JPanel {
        private int xCoord;
        private int yCoord;
    
        public int getxCoord() {
            return xCoord;
        }
    
        public void setxCoord(int xCoord) {
            this.xCoord = xCoord;
        }
    
        public int getyCoord() {
            return yCoord;
        }
    
        public void setyCoord(int yCoord) {
            this.yCoord = yCoord;
        }
    
        public Wall(int x, int y) {
            this.xCoord = x;
            this.yCoord = y;
        }
    
        public void moveWall(int xUnits, int yUnits) {
            xCoord += xUnits;
            yCoord += yUnits;
            repaint();
        }
    
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 400);
        }
    
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;
            g2d.setColor(Color.BLUE);
    
            g2d.fill(new Rectangle2D.Double(xCoord, yCoord, 100, 20));
        }
    }
    

    Which will produce a similar output like this one:

    这篇关于一旦 JComponent 离开屏幕,它就会停止渲染的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆