我想使用ScrollPane在其视口中显示图像,并且在图像上还有一个网格(或框,或任何其他类型的注册/位置标记)。滚动时我需要叠加层保持固定(意味着图像似乎在叠加层下“移动”)。我将以固定速率在视口中滚动视图以提供平滑运动,并且叠加将提供对视口内某个位置的引用。从概念上讲,考虑在视口中滚动的大型地图,以及具有不移动的矩形的视口(相对于视口本身),该矩形标记可以根据某些用户操作放大的区域。
我假设(但尚未确认)ScrollPane实现有效地处理View的渲染(来自后备存储,不必为每个新的部分曝光重新绘制整个View(甚至ViewPort))因此不希望必须覆盖paint()方法。
我看过LayerPane,虽然没有掌握它,但似乎这是一种蛮力方法。 ScrollPane是SplitPane的一个组件,将被移动/调整大小。我希望我必须使用绝对定位手动维护ViewPort和LayerPane之间的正确关系。我远不是GUI设计和专家的专家。实施,我确信我错过了从有经验的人会知道的明显到模糊和优雅的可能性。
我愿意接受任何建议,而不仅仅是我开始的道路。我是否(我可以)在我的SplitPane中添加JPanel作为一个组件,然后在LayerPane的不同图层上添加一个LayerPane到包含我的ScrollPane和覆盖(另一个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);
}
}
答案 0 :(得分:7)
通常,“Swing程序应该覆盖paintComponent()
而不是覆盖paint()
”,如Painting in AWT and Swing: The Paint Methods中所述。基于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)来修复它。