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

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

问题描述

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



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



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

  package graphics.simpleAnimation; 

公共类Simple_Animation实现Runnable {

private UI ui; // UI(框架)

私人墙; //在屏幕上移动的Wall对象

private Simple_Animation(){

//初始化wall对象(故意给出一个大于帧宽度的x值)
wall = new Wall(1100,400,200,400);

//初始化UI(宽度仅为1000)
ui =新UI(1000,600,Geometry Dash);

//将墙添加到ui(框架)
ui.add(墙);

}

public void run(){
//设置框架可见
ui.setVisible(true);

//重绘框架并移动墙
while(true){
ui.repaint();
wall.moveWall(-2,0);

try {
Thread.sleep(16);
} catch(InterruptedException IE){
System.out.println(IE);
}

}

}

//在新线程中启动程序
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。*;

公共类UI扩展JFrame {

//存储内容窗格的宽度和高度的变量(呈现组件的位置)
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。*;

公共类Wall扩展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(){
返回新维度(wallW,wallH);
}

@Override
public void paintComponent(Graphics g){
Graphics2D g2d =(Graphics2D)g;

setLocation(wallX,wallY);
g2d.fillRect(0,0,wallW,wallH);
}
}


解决方案

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


  1. 你使用的是 null layout ,请参阅


    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天全站免登陆