Java:如何在 ScrollPane Viewport 上绘制非滚动覆盖?

标签 java swing graphics overlay scrollpane

我想使用 ScrollPane 在其视口(viewport)中显示图像,并在图像上覆盖一个网格(或框,或任何其他类型的注册/位置标记)。我需要覆盖层在滚动时保持固定(这意味着图像似乎在覆盖层“下方”移动)。我将以固定的速率在视口(viewport)中 ScrollView 以提供平滑的运动,叠加层是为了提供对视口(viewport)内特定位置的引用。从概念上讲,想象一个大 map 在视口(viewport)中滚动,并且视口(viewport)有一个不移动的矩形(相对于视口(viewport)本身),它标记了一个区域,该区域可以根据某些用户操作放大。

我假设(但尚未确认)ScrollPane 实现可以有效地处理 View 的渲染(从后备存储,不必为每个新的部分曝光重新绘制整个 View (甚至 ViewPort)),因此不希望必须重写 paint() 方法。

我看过 LayerPane,虽然没有掌握它,但似乎这是一种蛮力方法。 ScrollPane 是 SplitPane 的一个组件,将被移动/调整大小。我希望我必须使用绝对定位手动维护 ViewPort 和 LayerPane 之间的正确关系。我远不是 GUI 设计和实现方面的专家,而且我确信我错过了经验丰富的人会知道的从明显到晦涩和优雅的各种可能性。

我愿意接受任何建议,而不仅仅是我已经开始的道路。我是否应该(可以)在我的 SplitPane 中添加一个 JPanel 作为一个组件,然后将一个 LayerPane 添加到包含我的 ScrollPane 的组件中,并在 LayerPane 的不同层上覆盖(另一个​​ JPanel)? ScrollPane 中是否有直接支持此功能的功能?我查看了 Java Swing 教程和 API 文档,但还没有看到任何内容。

谢谢。

更新:

谢谢你的链接,trashgod。这比我预期的要容易得多。不需要 LayerPane、GlassPane、基于异或的合成……我不知道为什么我没有想到尝试重写 JViewport.paint() 来绘制我的叠加层——但使用下面的代码我验证了这个概念将给我我要找的东西。只需使用 JViewport 的子类,它就会执行我想要的操作(在本例中,在 Viewport 的中心覆盖一个矩形,而图像在下方滚动)。我不是 GUI 专家,而且 Java API 非常广泛;我不知道你们是怎么把这些都记在脑子里的——但是谢谢!

class MyViewport extends JViewport {
    @Override
    public void paint(Graphics g) {
        super.paint(g);
        Graphics2D g2 = (Graphics2D)g;
        g2.setPaint(Color.BLACK);
        g2.drawRect(getWidth()/4,getHeight()/4,getWidth()/2,getHeight()/2);
    }
}

最佳答案

通常,“Swing 程序应该覆盖 paintComponent() 而不是覆盖 paint(),”如 Painting in AWT and Swing: The Paint Methods 中所述.基于ScrollPanePaint ,它在滚动内容下方绘制,以下示例重写 paint() 以在滚动内容上方绘制。

ScrollPanePaint

import java.awt.*;
import javax.swing.*;

/**
 * @see https://stackoverflow.com/a/10097538/230513
 * @see https://stackoverflow.com/a/2846497/230513
 * @see https://stackoverflow.com/a/3518047/230513
 */
public class ScrollPanePaint extends JFrame {

    private static final int TILE = 64;

    public ScrollPanePaint() {
        JViewport viewport = new MyViewport();
        viewport.setView(new MyPanel());
        JScrollPane scrollPane = new JScrollPane();
        scrollPane.setViewport(viewport);
        this.add(scrollPane);
        this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        this.pack();
        this.setLocationRelativeTo(null);
        this.setVisible(true);
    }

    private static class MyViewport extends JViewport {

        public MyViewport() {
            this.setOpaque(false);
            this.setPreferredSize(new Dimension(6 * TILE, 6 * TILE));
        }

        @Override
        public void paint(Graphics g) {
            super.paint(g);
            g.setColor(Color.blue);
            g.fillRect(TILE, TILE, 3 * TILE, 3 * TILE);
        }
    }

    private static class MyPanel extends JPanel {

        public MyPanel() {
            this.setOpaque(false);
            this.setPreferredSize(new Dimension(9 * TILE, 9 * TILE));
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.lightGray);
            int w = this.getWidth() / TILE + 1;
            int h = this.getHeight() / TILE + 1;
            for (int row = 0; row < h; row++) {
                for (int col = 0; col < w; col++) {
                    if ((row + col) % 2 == 0) {
                        g.fillRect(col * TILE, row * TILE, TILE, TILE);
                    }
                }
            }
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new ScrollPanePaint();
            }
        });
    }
}

注意: 将不透明组件(例如 JTable )设置为滚动 Pane 的 View 会产生奇怪的视觉错误,例如在滚动时移动固定的蓝色框。在 View 组件上使用 setOpaque(false) 来解决这个问题。

关于Java:如何在 ScrollPane Viewport 上绘制非滚动覆盖?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10093425/

相关文章:

java - 包含任意对象的 ArrayList

java - 访问当前进程句柄

java - 在线程运行时更改 JProgressBar 值

java - 有没有一种简单的方法可以在获得焦点时更改 Java/Swing 控件的行为?

java - 当我在选择 0 索引的情况下删除和添加时,Swing JList 卡住

java - 字符串数组转入HashMap集合对象

java - 使用 Selenium Webdriver 在文本区域键入 TAB

c# 填充除 GraphicsPath 以外的所有内容

C#/Silverlight/WPF/快速渲染大量圆圈

python - 使用 Python 确定图像是否存在于更大的图像中,如果存在,则找到它