本文介绍了一旦 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. (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 离开屏幕,它就会停止渲染的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-31 10:41