animation pipeline using swing
我尝试优化应用程序的图形。目前,我已经实现了动画以及一些GUI组件。有些是完全分开的,有些是彼此重叠的。目前,我在挥杆组件的重叠部分面临一个问题。 GUI的一部分与我的动画重叠,需要绘制许多字符串,并在放置的Jlist中绘制常见的挥杆组件。
结果是,随着动画的更新,重叠的GUI会被重绘。我尝试使用许多不同的方法来确保彼此之间得出的结论。诸如GlassPane,Jlayeredpane之类的东西。不幸的是,在任何这些尝试中,仅当用户与之交互时才需要调用重叠的Menus paintcomponent方法,由于动画其频繁调用该方法,并且会导致相当高的CPU使用率。
我试图将菜单在Layeredpane中的位置较低,即:
1 2 3 4 | getLayeredPane().add(map, JLayeredPane.DEFAULT_LAYER); getLayeredPane().add(mapController, JLayeredPane.PALETTE_LAYER); getLayeredPane().add(settings, JLayeredPane.PALETTE_LAYER); getLayeredPane().add(painter, JLayeredPane.POPUP_LAYER); |
在画家的绘画过程中,我试图修改区域-即:
1 2 3 4 5 6 7 8 9 | @Override protected void paintComponent(Graphics g) { g2 = (Graphics2D)g; g2.setRenderingHints(DefaultResources.getRenderQuality()); g2.clip(JMain.getInstance().getMapBounds()); ...} |
好-画家组件!isOpague();下方的所有组件都会重绘。不幸的是,如果我确实将菜单置于较高的顺序,那么它们也需要在进行任何动画更新时重新绘制。
有人有什么想法,如何避免使用动画组件永久重绘重叠的组件?
我看到的唯一解决方案是使用重量级的容器。不幸的是,相对定位还显示了在移动目的期间的行为,这是不合适的。
感谢任何建议!
好吧,很明显,如果重叠的不透明组件全部都将在其中之一的任何更改上重新绘制,除非您优化了对某些特定矩形的动画重新绘制调用,所以不会有任何重叠无用的操作。
让我描述一下Swing的工作原理-您在paint,paintComponent和其他方法中所做的所有绘画(在每个组件重绘时都会调用)在包含" cached "的单个图像的子图像上完成。整个框架界面的版本。
现在,假设您在UI(添加/删除/重绘组件)中进行了某些更改-必须正确更新最终图像(或至少包含组件的一小部分)。如果您的组件不是不透明的,请执行此操作-所有子组件都将使用您的组件边界进行重新绘制,作为重新绘制矩形以为您的组件创建适当的背景。如果您的组件是不透明的-它将是唯一一个重新绘制的对象,但是它也必须自己填充整个边界,否则每次重新绘制时,您都将在您的组件后面看到可怕的绘制工件。
总结一下-为避免重叠组件的无意义重绘,有几种方法:
根据您的具体情况,可能还会有更多的优化方法,但是您将不得不自己找到它们,因为如果不了解整个情况,这是不可能的。
您还可以在本书中找到有关Swing优化的许多有用信息:肮脏的富客户端
好的,我们去了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | 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的组件,这些JList具有许多String绘制任务,这实际上对cpu的使用有很大的影响。我一直在想,因为它每秒被重绘大约25次。
对于当前的解决方案,我只是不确定,如果立即使用paint是合适的。除此之外-如果您或其他人有另一种-更好的方法-防止无用的重绘(我真的认为Glasspane或JLayeredPane或isOptimizedDrawing或isOpaque可能会有所帮助),我真的很感谢。
最诚挚的问候。
在优化方面,我确实有一个组件,这引起了很多麻烦,但是我计划重写它。因此,我只想确保绘画区域正确。在那之后,我已经计算了所有必要的区域并将它们填充到一个列表中,当数据更改时我将其通过。
只要我仅应用一个矩形,它就可以正常工作。一旦我通过了第二个,似乎它的y-扩展名就被忽略了。例如:
[x = 0,y = 0,width = 322,height = 20]
[x = 0,y = 620,width = 322,height = 20]
在y = 20到y = 620之间的所有内容也会重新绘制。
1 2 3 |
好吧,我已经在EDT中立即进行了paint操作,目前该方法确实有效,但是我想知道这是否是一种正确的方法:
1 2 3 4 5 6 7 8 | SwingUtilities.invokeLater(new Runnable() { public void run() { for (Rectangle rec : clippingAreas) { painter.paintImmediately(rec); } } }); |