Java-Swing自绘组件在鼠标不移动时降低帧率(仅限Linux)

问题描述 投票:-1回答:1

使用JPanel运行一个简单的Swing应用程序,定期重新绘制(通过Timer或Network-Activity),会触发paint / paintComponent方法,但只要鼠标移动,屏幕上生成的图像才会更新在窗前。

使用X11和Wayland在Ubuntu下使用以下最小应用程序可以重现这一点。它似乎不能在Windows下重现。使用GTK的类似Python-Application没有出现这个问题,它似乎非常特定于Java。

package de.mazdermind;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

public class Main {

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> {
            JFrame frame = new JFrame();
            frame.setTitle("SwingBackgroundDrawExperiment");

            frame.setSize(800, 600);
            frame.add(new CustomPanel());
            frame.setVisible(true);
        });
    }

    public static class CustomPanel extends JPanel implements ActionListener {

        private int n = 0;

        public CustomPanel() {
            Timer timer = new Timer(20, this);
            timer.start();
        }

        @Override
        protected void paintComponent(Graphics g) {
            System.out.println("painting");
            g.clearRect(0, 0, getWidth(), getHeight());

            g.setColor(Color.RED);
            g.fillRect(0, n % getHeight(), getWidth(), 10);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            n++;
            System.out.println("scheduling repaint on GUI-Thread");
            EventQueue.invokeLater(() -> {
                System.out.println("requesting repaint");
                repaint();
            });
        }
    }
}

这是一个揭示问题的示例的屏幕截图:qazxsw poi

动画开始流畅但很快变得邋((即在1fps到0.5fps之间)。只要鼠标在窗口前移动,它就会再次变得平滑,但在秒内它停止移动,动画再次变得邋..

我希望动画能够同样快速地独立于鼠标移动。

Test-Environment是Ubuntu 18.04.2,Ubuntu附带OpenJDK 1.8:

https://youtu.be/5zLCMVLrd6M
java swing ubuntu gtk gnome
1个回答
2
投票

这似乎对我有用吗?问题表现出来需要多长时间?我正在运行Windows 10。

另外,我确实有一些建议。

这允许您正常关闭窗口。

openjdk version "1.8.0_191"
OpenJDK Runtime Environment (build 1.8.0_191-8u191-b12-2ubuntu0.18.04.1-b12)
OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)

你应该在paintComponent方法中调用以下第一件事。

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

然后,它将清除面板以显示下一个涂料,并将任何默认颜色应用于面板

最后,在您的actionPerformed方法中,您已经在EDT中,因此您可以调用repaint()并为您安排它。无需启动另一个线程。

© www.soinside.com 2019 - 2024. All rights reserved.