【问题标题】:animation pipeline using swing使用摆动的动画管道
【发布时间】:2012-09-22 08:27:10
【问题描述】:

我尝试优化我的应用程序的绘图。目前我已经实现了一个动画以及几个 GUI 组件。有些是完全分开的,有些是相互重叠的。目前我面临摆动组件重叠的问题。 GUI 的一部分,与我的动画重叠,需要绘制大量字符串和 - 放入 Jlist 中 - 常见的摆动组件。

结果,重叠的 GUI 会随着动画的更新而重绘。我尝试使用很多不同的方法来确保在彼此面前绘制的内容。 GlassPane、Jlayeredpane 之类的东西。不幸的是,在这些尝试中,重叠的 Menus paintcomponent 方法(仅在用户与其交互时才需要调用)由于动画而被频繁调用并导致相当高的 cpu 使用率。

我尝试在分层窗格中以较低的顺序放置菜单,即:

    getLayeredPane().add(map, JLayeredPane.DEFAULT_LAYER);
    getLayeredPane().add(mapController, JLayeredPane.PALETTE_LAYER);
    getLayeredPane().add(settings, JLayeredPane.PALETTE_LAYER);        
    getLayeredPane().add(painter, JLayeredPane.POPUP_LAYER);   

在画家的绘画过程中,我尝试修改该区域 - 即:

@Override
protected void paintComponent(Graphics g) {

    g2 = (Graphics2D)g;
    g2.setRenderingHints(DefaultResources.getRenderQuality());

    g2.clip(JMain.getInstance().getMapBounds());

    ...}

好吧 - 只要画家组件 !isOpague();下面的所有组件都将重新绘制。不幸的是,如果我确实将菜单置于更高的顺序,它们也需要随着任何动画更新而重新绘制。

有人知道如何避免使用动画组件永久重绘重叠组件吗?

我见过的唯一解决方案是使用重量级容器。不幸的是,相对定位在移动目的期间也表现出一种行为,这是不合适的。

感谢您的任何建议!

【问题讨论】:

  • 1.请问g2.clip(JMain.getInstance().getMapBounds()); 是什么,2. 为获得更好的帮助,请尽快发布SSCCE 演示导致的问题

标签: java swing animation paint jlayeredpane


【解决方案1】:

嗯,很明显,如果您有重叠的非透明组件,除非您优化对某些特定矩形的动画重绘调用,否则所有这些组件都将根据其中一个的任何更改进行重绘,因此不会有任何无用的操作。

让我更详细地描述一下 Swing 的工作原理 - 您在 paint、paintComponent 和其他方法(在每个组件重绘时调用)中所做的所有绘画都是在包含“缓存”版本的单个图像的子图像上完成的整个框架界面。

现在假设您更改了 UI 中的某些内容(添加/删除/重绘组件) - 最终图像(或包含您的组件的至少一小部分)必须正确更新。要做到这一点,以防您的组件不是不透明的 - 所有子组件都将使用您的组件边界作为重绘矩形重新绘制,以为您的组件创建适当的背景。如果您的组件是不透明的 - 它将是唯一一个重绘的组件,但它还必须自己填充整个边界矩形,否则您将在每次重绘时在组件后面看到可怕的绘画伪影。

总结 - 为了避免重叠组件的无意义重绘,有几种方法:

  1. 优化动画重绘调用到您实际需要重绘的区域
  2. 使用不透明的组件,除非您想在组件中绘制透明的东西
  3. 优化所有重叠组件的绘制操作,以便重新绘制不会花费太多时间

根据您的具体情况,可能还有更多优化方法,但您必须自己找到它们,因为如果不看全貌,这是不可能的。

您还可以在本书中找到很多关于 Swing 优化的有用信息:Filthy Rich Clients

【讨论】:

  • 嘿,非常感谢这些答案。我已经尝试完全按照您在 1. 方法中所做的描述。例如,我制作了一个 Area 对象,它具有我的地图的边界。接下来我减去了菜单的边界。在那里,我已经剪辑了重绘,如我第一篇文章中的源代码所示。不幸的是,即使重叠地图没有在我的菜单范围内绘制任何内容,菜单的paintcomponent 方法也会被调用。我也试图让那个不透明,把它放在地图的顶部或下面——它仍然会被调用。我可以防止吗?
  • 嗯,我刚刚看到,你提到的区域是什么意思。因此我需要告诉重绘边界,这将被重绘。对于一个剪辑,我已经在paintcomponent 方法中,它触发了那些菜单。是否有某种机会在重绘调用中转发形状而不是矩形?
  • @user1514195 nop,你只能在重绘某些东西时使用矩形。所以你必须明智地选择重新粉刷的区域。调用少量重绘而不是单个重绘可能也很有用,以防它可能会从重绘中排除一些覆盖组件。仍然确保将获得多次重绘调用的组件具有优化的绘制方法。
  • 在“优化的绘画方法”方面,你有什么特别的想法吗?我的或多或少是几个依赖于数据模型的静态绘图方法,这些数据模型的变化独立于绘画算法。因此我不创建任何对象或某事。
  • @user1514195 “优化”的意思是“针对您的特定情况进行了优化”。没有通用/简单的方法来提高绘画性能。有一些通用提示和技巧可能会有所帮助,但如果使用不当,它们也可能会降低性能。如果您有一些数据模型应该在其更改上更新 UI - 收集更改并将它们全部应用,优化您的重绘调用,删除不必要的重绘调用,如果需要,正确剪辑绘画区域。实际上,这些都是适用于任何情况的一般提示。
【解决方案2】:

在优化方面,我确实有一个组件,这会造成相当大的麻烦,但我计划重写那个组件。因此,我只想确保绘画区域正确。在那之后,我计算了所有必要的区域并将它们填充到一个列表中,当数据发生变化时我将其传递。

只要我只应用了一个矩形,它就可以正常工作。一旦我通过第二个,它的 y - 扩展似乎就被忽略了。例如:

[x=0,y=0,宽度=322,高度=20] [x=0,y=620,宽度=322,高度=20]

y=20 和 y=620 之间的所有内容也会被重绘。

for (Rectangle rec : clippingAreas) {                    
                 painter.repaint(rec);
            }

好的,我已经在 EDT 中尝试了paintImmediately,它现在确实有效,但我想知道这是否是正确的方法:

SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                for (Rectangle rec : clippingAreas) {
                    painter.paintImmediately(rec);                        
                }
            }
        });

【讨论】:

  • 如果我使用 myPainter.paintImmediately(rec),它可以工作,但它确实会产生相当多的绘画工件。
  • 你究竟是如何“通过第二个”的?您能否显示重新绘制两个矩形的确切代码?
  • for (Rectangle rec : clippingAreas) {painter.repaint(rec); }
  • 问题是,如果我对一个简单的示例(如 3-4 个重叠组件)进行这样的重绘 - 一切都将按照应有的方式重绘。因此,我建议您搜索代码中的问题,应该存在某种错误或至少是误解。
  • 我对你所说的又多了一个想法——你说你重新绘制了 y[0-20] 和 y[620-640] 区域。您是否有任何与它们相交并位于这些区域之间的组件?
【解决方案3】:

好的,我们开始:

package animationissue;

import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;

public class AnimationIssue extends JFrame {

JPanel a = new JPanel() {

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        System.out.println("map has become repainted");
    }
};
JPanel b = new JPanel() {

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        System.out.println("menu as well");
    }
};

public AnimationIssue() {
    this.setSize(500, 500);
    this.setLayout(null);

    a.setSize(400, 400);
    b.setSize(400, 200);

    this.getLayeredPane().add(a, JLayeredPane.DEFAULT_LAYER); // Map
    this.getLayeredPane().add(b, JLayeredPane.PALETTE_LAYER); // Menu

    a.setLocation(0, 0);
    b.setLocation(0, 100);

    a.setBackground(Color.red);
    b.setBackground(Color.blue);



    Thread t = new Thread(new Runnable() {

        @Override
        public void run() {
            // doin some computations for animation
            // cast a repaint after having finished new 
            //animation information i.e. interpolation
            while (true) {
                try {
                    Thread.sleep(2000);
                } catch (Exception e) {
                }

                // case 1 - just a repaint of the whole component - triggering map redraw results in menu redraw
                // a.repaint();

                // case 2 - repaint of specified rectangle 
                // Either passing one - the menu does not get repainted, or passing       both - menu also gets repainted       

                //a.repaint(0, 0, 400, 100);
                //a.repaint(0, 300, 400, 100);

                // paintimmediately works for now

                //a.paintImmediately(0, 0, 400, 100);
                //a.paintImmediately(0, 300, 400, 100);

                // Just repainting Menu does not trigger map to become repainted, except if its opague, but then it should become repainted
                b.repaint();


            }

        }
    });

    t.start();
}

/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    // TODO code application logic here
    AnimationIssue f = new AnimationIssue();
    f.setVisible(true);
}

}

我真的很期待优化行为,如果没有必要,不会重绘菜单。您必须将菜单想象成一个包含多个 JList 的组件,其中包含大量 String 绘制任务,这对 cpu 使用率确实有巨大影响。我一直没有想知道,因为它每秒重绘大约 25 次。

如果使用paintImmediately 是否合适,我只是不确定当前的解决方案。除此之外 - 如果你或某人有替代 - 更好 - 防止无用重绘的方法(我真的认为 Glasspane 或 JLayeredPane 或 isOptimizedDrawing 或 isOpaque 可能会有所帮助),我真的很感激。

最好的问候。

【讨论】:

  • 没有其他人提供的信息?就像我要利用某事一样。除了paintImmediately?!
猜你喜欢
  • 1970-01-01
  • 2012-09-16
  • 1970-01-01
  • 2023-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多