Java:如何在ScrollPane视口上绘制非滚动叠加层? [英] Java: How to draw non-scrolling overlay over ScrollPane Viewport?

查看:224
本文介绍了Java:如何在ScrollPane视口上绘制非滚动叠加层?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



我假设(但尚未确认)ScrollPane实现可以高效地处理View的呈现(从后备存储,不必为每个新的部分曝光重新绘制整个View(甚至ViewPort) ),所以宁愿不必重写paint()方法。



我看了一下LayerPane,虽然没有掌握它,但看起来这是暴力方法。 ScrollPane是SplitPane的一个组件,将被移动/调整大小。我期望我必须使用绝对定位手动维护ViewPort和LayerPane之间的正确关系。我远不是GUI设计专家,实施,我确信我失去了从明显到晦涩和优雅的可能性,有经验的人会知道。



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



谢谢。



更新:

感谢您的链接,垃圾内容。这比我预期的要容易得多。不需要LayerPane,GlassPane,基于xor的合成...我不知道为什么我没有尝试覆盖JViewport.paint()来绘制覆盖图 - 但是通过下面的代码,我验证了这个概念给我我要找的东西。只需使用JViewport的子类,它就可以做我想做的事情(在这种情况下,在视图中心覆盖一个矩形,而图像在下面滚动)。我不是GUI专家,Java API非常宽泛;我不知道你们是如何把这一切都放在你的脑海里 - 但谢谢!

  class MyViewport扩展了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(),如)滚动窗格的视图会给出奇怪的视觉错误,例如在滚动时移动固定的蓝色框。在视图组件上使用setOpaque(false)来解决这个问题。


I'd like to use a ScrollPane to display an image in its Viewport, and also have a grid (or box, or any other type of registration/location marker) overlay on the image. I need the overlay to remain fixed when scrolling (meaning the image seems to move "under" the overlay). I will be scrolling the View in the Viewport at a fixed rate to provide a smooth motion, and the overlay is to provide a reference to a certain location within the Viewport. Conceptually, think of a large map scrolling in a Viewport, and the Viewport having a rectangle that does not move (relative to the Viewport itself) that marks a region that can be zoomed into based on some user action.

I presume (but have not yet confirmed) that the ScrollPane implementation handles rendering of the View efficiently (from backing store, not having to repaint the entire View (or even ViewPort) for each new partial exposure) and so would prefer not to have to Override the paint() method.

I've looked at LayerPane, and while not having mastered it, it seems that this is a brute force approach. The ScrollPane is one Component of a SplitPane and will be moved/resized. I expect that I'd have to manually maintain the correct relationship between the ViewPort and the LayerPane using absolute positioning. I'm far from an expert in GUI design & implementation and I'm sure I'm missing possibilities ranging from obvious to obscure and elegant that an experienced person would know.

I'm open to any suggestions, not just the path I've started down. Should I (can I) add a JPanel as one component in my SplitPane, then add a LayerPane to that containing my ScrollPane and the overlay (another JPanel) on different layers on the LayerPane? Is there functionality in ScrollPane to support this directly? I've looked at the Java Swing Tutorials and the API documentation but haven't seen anything yet.

Thanks.

UPDATE:

Thanks for the link, trashgod. This was much easier than I had expected. No need for LayerPane, GlassPane, xor-based compositing... I don't know why it didn't occur to me to try overriding JViewport.paint() to draw my overlay - but with the code below I validated the concept will give me what I'm looking for. Just use the subclass of JViewport and it does what I wanted (in this case overlaying a rectangle in the center of the Viewport while the image scrolls underneath). I'm no GUI expert, and the Java API is incredibly wide; I have no idea how you guys keep this all in your head - but thanks!

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);
    }
}

解决方案

Ordinarily, "Swing programs should override paintComponent() instead of overriding paint()," as mentioned in Painting in AWT and Swing: The Paint Methods. Based on ScrollPanePaint, which draws below the scrolling content, the following example overrides paint() to draw above the scrolling content.

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();
            }
        });
    }
}

Note: Setting an opaque component (for instance JTable) as a view for the scroll pane will give strange visual bugs, for instance moving the fixed blue box when scrolling. Use setOpaque(false) on the view component to fix that.

这篇关于Java:如何在ScrollPane视口上绘制非滚动叠加层?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆