【问题标题】:Does g.drawImage() render only the part of the image visible on a JPanel, or does it "keep in mind" the rest of the image?g.drawImage() 是否仅渲染 JPanel 上可见的图像部分,还是“记住”图像的其余部分?
【发布时间】:2013-05-14 04:08:38
【问题描述】:

假设我们有以下代码:

(在扩展 JPanel 的类中):

public void paintComponent(Graphics g) {
    g.drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null);
}

如果dx1dy1 为负数或dx2dy2 大于JPanel 的宽度(换句话说,部分图像将在屏幕外),@987654328 @调整渲染的内容,使其仅“关注”JPanel 上可见的部分?我对此感到好奇,因为如果我在JPanel 上绘制一个非常大的图像,paintComponent() 可能会变慢。

【问题讨论】:

  • Graphics 对象有一个“剪辑”集。我相信默认是组件边界。
  • 试试这样的。将剪辑区域设置为小于可见区域,在其上绘制一些东西,然后重置剪辑并绘制其他东西,看看你得到了什么
  • g.drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null); 应该是g.drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, this);
  • 观察者到底为我做了什么?
  • ImageObserver API 是怎么说的?

标签: java swing jpanel implementation paintcomponent


【解决方案1】:

这里有两个方面的问题......

1.加载大图

您已经在代码示例中将一个大图像加载到内存中(您正在将其直接绘制到组件上)。这意味着,如果您将拥有一个非常大的图像 - 当您开始将其加载到内存中进行绘制时,您会遇到第一个问题(实际上并不重要) - 它会消耗 大量 内存满载时。

当您处理大图像时,这应该是最令人头疼的问题,因为标准 Java 并没有提供很多工具。您只能使用基本工具加载完整图像。

您可能想研究一些替代方法来加载图像的一部分(不确定是否总是可行)或将大图像分割成多个部分并仅加载显示的图像部分。像 JAI 这样的第三方库可能会对此有所帮助。

不管怎样,这都是“歌词”——我们来看看你问的第二个问题。

2。在组件上绘制大图像

我敢打赌,您已经阅读了一些 Swing 教程,并且您可能知道该剪辑。您可能还知道它通常设置为组件的当前 visible 边界。是的,只有可见的部分。

因此,如果您有类似 5000x5000 像素大小的面板,上面绘有 5000x5000 像素图像,但面板的可见部分仅为 500x500 像素 - 图像也将被底层图形剪裁,只有适合的部分剪辑将被绘制。

此优化也适用于各种形状的绘画/填充和其他图形操作。这不是一件显而易见的事情,但在大多数情况下,最好绘制完整的形状/图像并让底层图形优化绘制操作。在大多数情况下,这将比手动剪切形状/图像并绘制结果要快几倍。

还有一件事 - 在图形上绘制图像是 Graphics2D 中最快的操作之一,所以我不会真正关注它。

您可以查看这个小示例,它清楚地表明 Graphics2D 内部实现提供的绘画优化:

public class ImageDrawTest
{
    public static void main ( String[] args )
    {    
        final ImageIcon icon = new ImageIcon ( "C:\\large.jpg" );

        JComponent c = new JComponent ()
        {
            protected void paintComponent ( Graphics g )
            {
                super.paintComponent ( g );

                long time = System.nanoTime ();
                g.drawImage ( icon.getImage (), 0, 0, null );
                time = System.nanoTime () - time;
                System.out.println ( time );
            }
        };

        JFrame f = new JFrame ();
        f.getContentPane ().setLayout ( new BorderLayout () );
        f.getContentPane ().add ( c );
        f.setSize ( 200, 100 );
        f.setLocationRelativeTo ( null );
        f.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
        f.setVisible ( true );
    }
}

使用任何可用的大图像路径代替C:\\large.jpg

只需运行此示例并调整框架大小以更改组件的可见区域以查看输出。它会以纳秒为单位显示每次重绘的绘制时间 - 根据可见区域的大小,它会有很大差异。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-04
    • 1970-01-01
    • 1970-01-01
    • 2013-03-03
    • 2011-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多