簡體   English   中英

Java:如何在 ScrollPane Viewport 上繪制非滾動覆蓋?

[英]Java: How to draw non-scrolling overlay over ScrollPane Viewport?

我想使用 ScrollPane 在其視口中顯示圖像,並在圖像上覆蓋一個網格(或框,或任何其他類型的注冊/位置標記)。 我需要覆蓋層在滾動時保持固定(這意味着圖像似乎在覆蓋層“下方”移動)。 我將以固定的速率在視口中滾動視圖以提供平滑的運動,疊加層是為了提供對視口內特定位置的引用。 從概念上講,想象一個大的 map 在 Viewport 中滾動,並且 Viewport 有一個不移動的矩形(相對於 Viewport 本身),它標記了一個可以根據某些用戶操作放大的區域。

我假設(但尚未確認)ScrollPane 實現可以有效地處理視圖的渲染(從后備存儲,不必為每個新的部分曝光重新繪制整個視圖(甚至 ViewPort)),因此我寧願不必覆蓋 paint() 方法。

我看過 LayerPane,雖然沒有掌握它,但似乎這是一種蠻力方法。 ScrollPane 是 SplitPane 的一個組件,將被移動/調整大小。 我希望我必須使用絕對定位手動維護 ViewPort 和 LayerPane 之間的正確關系。 我遠不是 GUI 設計和實現方面的專家,而且我確信我錯過了經驗豐富的人會知道的從明顯到晦澀和優雅的可能性。

我願意接受任何建議,而不僅僅是我已經開始的道路。 我是否應該(可以)在我的 SplitPane 中添加一個 JPanel 作為一個組件,然后將一個 LayerPane 添加到包含我的 ScrollPane 的組件中,並在 LayerPane 的不同層上覆蓋(另一個 JPanel)? ScrollPane 中是否有直接支持此功能的功能? 我查看了 Java Swing 教程和 API 文檔,但還沒有看到任何內容。

謝謝。

更新:

感謝您的鏈接,trashgod。 這比我預期的要容易得多。 不需要 LayerPane、GlassPane、基於 xor 的合成……我不知道為什么我沒有想到嘗試覆蓋 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() ”,如AWT 中的繪畫和 Swing:繪畫方法中所述。 基於在滾動內容下方繪制的ScrollPanePaint ,以下示例重寫paint()以在滾動內容上方繪制。

滾動面板繪制

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 )設置為滾動窗格的視圖會產生奇怪的視覺錯誤,例如在滾動時移動固定的藍色框。 在視圖組件上使用setOpaque(false)來解決這個問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM