如何在Swing中合并重新绘制?

3
我从监听器中调用了多次repaint,但我的绘制函数只需要一次repaint。由于它与鼠标移动监听器相连,我生成了大量的repaints。
有没有办法取消某个组件的所有待处理repaints?我不能简单地开始忽略repaints,因为有些是有效的,比如当你调整框架大小或从最小化状态还原时。
为什么我要在意呢?因为我的绘制代码非常耗费资源,我无法以非常高的FPS进行全面的repaint。
5个回答

2

频繁的重绘请求会自动合并成一个。优化的最佳方式不是重新绘制整个图形,而是调用具有特定区域坐标的重绘方法。这意味着您只需重新绘制实际更改的区域。


2
Swing 将为您合并重绘操作:请参阅 Sun 公司网站上的"AWT和Swing中的绘图"。如果您快速安排了一系列重绘操作,它们将被合并为一次对paintImmediately()方法的调用。

1
我的理解是repaint()只是通过将组件的区域添加到重绘队列中来安排重绘。如果已经请求了组件上的重绘,则新的重绘区域将与先前请求的区域联合。重绘实际上直到事件队列中的所有其他事件都处理完毕才会执行。因此,您的额外重绘可能不会有太大的影响,即您的绘画代码仅会执行一次。请参见JComponent.repaintRepaintManager.addDirtyregion

0

我明白你的意思。 确实可以只重新绘制部分区域。 在Sun网站的“执行自定义绘画示例”中,我找到了一个有用的示例,展示了如何绘制拖动的矩形,然后仅在鼠标移动或释放时重新绘制该区域。

以下是相关代码段...

public void mouseDragged(MouseEvent e) {
            updateSize(e);
        }

        public void mouseReleased(MouseEvent e) {
            updateSize(e);
        }

        /* 
         * Update the size of the current rectangle
         * and call repaint.  Because currentRect
         * always has the same origin, translate it
         * if the width or height is negative.
         * 
         * For efficiency (though
         * that isn't an issue for this program),
         * specify the painting region using arguments
         * to the repaint() call.
         * 
         */
        void updateSize(MouseEvent e) {
            int x = e.getX();
            int y = e.getY();
            currentRect.setSize(x - currentRect.x,
                                y - currentRect.y);
            updateDrawableRect(getWidth(), getHeight());
            Rectangle totalRepaint = rectToDraw.union(previousRectDrawn);
            repaint(totalRepaint.x, totalRepaint.y,
                    totalRepaint.width, totalRepaint.height);
        }

此代码受版权保护(请参见此处以获取完整的代码和版权声明

请参见此处以获取更多示例列表

说实话,我在FPS上遇到了类似的问题,但这可能是由于我目前的代码质量较差!在过去的几个月中,我学到了很多东西,现在可以让我的代码更加高效。希望当超过2个“人”减慢我的图形时,我可以克服FPS问题!嗯...... 我只在我的代码中实现了上述代码的同一部分,而不是其他部分,但请尽管试试!


0

我已经拼凑出了类似的东西,以改进JFreechart在进行大量重绘调用时决定绘制的方式。

基本上我做以下事情:

  • 在类中创建一个ScheduledExecutorService字段
  • 接收第一次重绘请求并将其submit到执行器中,在50ms后在EDT上运行并返回未来结果
  • 接收第二个请求-测试上一个重绘是否完成(fut.isDone()),如果是,则安排下一个重绘;否则什么也不做。

这样,你应该每秒最多获得20个重绘请求。

当同时发生许多更改时,我也做了类似的批处理调用fireDataTableChanged的事情。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接