2

我尝试优化我的应用程序的绘图。目前我已经实现了一个动画以及几个 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(); 下面的所有组件都将重新绘制。不幸的是,如果我确实将菜单放在更高的顺序,它们也需要随着任何动画更新而重新绘制。

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

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

感谢您的任何建议!

4

3 回答 3

3

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

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

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

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

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

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

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

于 2012-10-01T13:54:50.293 回答
0

好的,我们开始:

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 可能会有所帮助),我真的很感激。

此致。

于 2012-10-04T12:05:03.657 回答
0

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

只要我只应用了一个矩形,它就可以正常工作。一旦我通过第二个,它的 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);                        
                }
            }
        });
于 2012-10-02T12:56:36.720 回答