0

我有一个JScrollPane显示(作为它的视口视图)MyPanel,一个JPanel.

MyPanel通过重载实现自定义绘画paintComponent。的可显示内容的总大小MyPanel通常很宽(意味着比JScrollPane视口的大小宽 50 倍到 200 倍)并且使用Timer,我水平滚动以查看底层的不同部分MyPanel。我还允许使用滚动条拇指手动寻找MyPanel.

在我的paintComponent实现中,我目前正在MyPanel使用 查找当前在视口中可见的部分JViewport#getVisibleRect,并且每次更改视口位置时只需绘制该部分。

这很好用——但我最终会MyPanel一遍又一遍地重新绘制可见部分的很大一部分,因为定时滚动一次只会将视口移动 1/50 的视口宽度。此外,我通常最终会滚动浏览 的整个水平范围MyPanel,因此无论如何我都必须至少绘制一次。

这让我想到MyPanel只绘制一次的全部内容(到一个BufferedImage?),然后让JScrollPane(或JViewport)处理剪辑和只对BufferedImage.

直觉上,在我看来,这似乎是处理这个问题的最有效方式,而且是相对常见的。

当我研究 Swing 教程和其他资源时,我了解到 Swing 已经是双缓冲的。如果我尝试用我自己的蛮力来强制执行此操作,而不依赖于 Swing 功能,听起来我最终会使用三重缓冲。

我还没有找到JScrollPane为我做这件事的方法(如果存在的话)。

是否有可用的示例或有关如何执行此操作的某些方向(如果可能)?

4

1 回答 1

0

Swing 仅自动为您绘制组件的最小必要区域。repaint(4 args)仅当组件部分更改并且您不希望重新绘制整个可见区域时才有用。而在你的实践中,它的效果与repaint(no-args).

如您在问题中所述,自动裁剪区域已经足够小,可以解决可见性问题。你可以在你的程序中配置它。

此外,您无需担心滚动—— JScrollPane 会自动调用其子项的重绘。

您可以轻松地尝试这些:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class Test extends JFrame {

    private Random rnd = new Random();
    private Color c = Color.WHITE;

    public Test () {
        final JPanel pnl = new JPanel() {

            @Override
            public void paintComponent (Graphics g) {
                super.paintComponent(g);
                g.setColor(c);
                g.fillRect(0, 0, getWidth(), getHeight());
                Rectangle r = g.getClipBounds();
                System.out.println(r.width + ", " + r.height);
            }
        };
        pnl.setPreferredSize(new Dimension(10000, 10000));

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(400, 400);
        setLocationRelativeTo(null);

        add(new JScrollPane(pnl));

        setVisible(true);

        new Thread() {

            @Override
            public void run () {
                while (true) {
                    c = new Color(rnd.nextInt(0xffffff));
                    pnl.repaint();
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {}
                }
            }
        }.start();
    }

    public static void main (String args[]) {
        new Test();
    }
}
于 2013-01-24T02:55:39.570 回答