2012-04-10 39 views
8

我想使用ScrollPane在其视口中显示图像,并在图像上叠加网格(或框或任何其他类型的注册/位置标记)。我需要覆盖层在滚动时保持固定(意味着图像似乎移动到覆盖层下)。我将以固定速率滚动视口中的视图以提供平滑的动作,并且叠加层将提供对视口内某个位置的引用。从概念上讲,可以考虑在Viewport中滚动的大型地图,并且Viewport具有一个不移动的矩形(相对于视口本身),该矩形标记可根据某些用户操作进行缩放的区域。我认为(但还没有确认)ScrollPane实现可以有效地处理View的渲染(从后台存储,不必为每个新的部分曝光重新绘制整个View(甚至ViewPort)),所以更喜欢不必重写paint()方法。Java:如何在ScrollPane视口上绘制非滚动叠加层?

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

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

谢谢。

UPDATE:

感谢您的链接,trashgod。这比我预期的要容易得多。不需要LayerPane,GlassPane,基于xor的合成...我不知道为什么我没有尝试覆盖JViewport.paint()来绘制覆盖图 - 但是通过下面的代码,我验证了这个概念给我我要找的东西。只需使用JViewport的子类,它就可以做我想做的事情(在这种情况下,在视图中心覆盖一个矩形,而图像在下面滚动)。我不是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); 
    } 
} 
+2

请参阅['ScrollPanePaint'](http://stackoverflow.com/a/3518047/230513)。更新:另见[*玻璃窗格*](http://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html#glasspane)。其中之一或两者都可以帮助您构建[sscce](http://sscce.org/)。 – trashgod 2012-04-10 18:30:08

+1

该链接只是我需要的正确方向的微调。用解决方案更新了问题。感谢垃圾。 – ags 2012-04-10 19:55:28

回答

7

通常情况下, “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)。在视图组件上使用setOpaque(false)来解决这个问题。

+0

为了暗示这种方法,可以使用@ags来表示赞赏。 – trashgod 2012-04-10 22:48:07

+0

@mKorbel:对不起,如果我没有按照协议在这里。有没有我错过的建议或问题? – ags 2012-04-11 19:57:24

+0

我碰到了一些模糊的提及paint()与paintComponent()的问题,但我需要做一些研究来理解差异以及何时适合。再次感谢指针。 – ags 2012-04-11 19:57:56

相关问题