带有LayoutManager的JLayeredPane

情况:绘制一堆扑克牌,就像在纸牌游戏中一样。 很好地堆积。

为此,我将JLayeredPaneLayoutManager接口的自定义实现结合使用。 使用自定义LayoutManager的原因是堆栈方向不同,有时候扑克牌完全相互覆盖,有时是部分覆盖,这个逻辑对于LayoutManager来说似乎是一个很好的工作,因为这基本上归结为设置的位置。牌。

因此, LayoutManager负责设置堆栈中所有组件的X坐标和Y坐标。 另一方面, JLayeredPane负责其Z坐标(通过其层)。

将组件添加到JLayeredPane是这样的:

 JLayeredPane pane = new JLayeredPane(); pane.setLayout(new StackLayout(...)); pane.add(new CardView(...), new Integer(j)); 

其中new Integer(j)是卡的一层。 由于JLayeredPane的合同,这必须是Integer

这里的问题是,由于上述原因,我的StackLayout不能有任何其他约束对象而不是IntegerLayoutManager接口要求您实现以下方法:

 addLayoutComponent(Component comp, Object constraints); 

并且传递的Object将始终为Integer

在我的特殊情况下,我很幸运,因为我的XY坐标可以根据Z坐标计算。 例如,层k的卡必须位于Y坐标k * offset 。 所以在我的情况下,约束对象是一个Integer不是问题。

我想知道当Z坐标和XY坐标之间没有相关性时你应该做什么? 你怎么解决这个问题呢? 例如,我如何将GridBagLayoutJLayeredPane结合使用,其中第一个需要GridBagConstraints对象,第二个需要Integer对象? 当然,GBL将以组件不重叠的方式布局,但这只是想法。

根据Hovercraft Full Of Eels的评论,我会回答我自己的问题。

调用JLayeredPane.add(Component comp, Object constraints)将调用addImpl(Component comp, Object constraints, int index) 。 这个方法被JLayeredPane本身覆盖,这里是源代码:

 protected void addImpl(Component comp, Object constraints, int index) { int layer; int pos; if(constraints instanceof Integer) { layer = ((Integer)constraints).intValue(); setLayer(comp, layer); } else layer = getLayer(comp); pos = insertIndexForLayer(layer, index); super.addImpl(comp, constraints, pos); comp.validate(); comp.repaint(); validateOptimizedDrawing(); } 

如您所见, Integer对象被截获,因此JLayeredPane知道应该放置comp的层。 然后,它将constraints (Integer)传递给超级实现。 超级实现Container的基本部分是:

 protected void addImpl(Component comp, Object constraints, int index) { ... if (layoutMgr != null) { if (layoutMgr instanceof LayoutManager2) { ((LayoutManager2)layoutMgr).addLayoutComponent(comp, constraints); } else if (constraints instanceof String) { layoutMgr.addLayoutComponent((String)constraints, comp); } } ... } 

因此,解决方案是扩展JLayeredPane并覆盖其addImpl(Component comp, Object constraints, int index)方法,该方法可以接受您选择的任何Object:此对象应包含JLayeredPane层决策所需的Integer ,它还应该包含所选LayoutManager的约束对象。

StackConstraints:

 public final class StackConstraints { public final int layer; public final Object layoutConstraints; public StackConstraints (int layer, Object layoutConstraints){ this.layer = layer; this.layoutConstraints = layoutConstraints; } } 

JLayeredPane扩展:

 protected void addImpl(Component comp, Object constraints, int index) { int layer; int pos; Object constr; if(constraints instanceof StackConstraints) { layer = constraints.layer.intValue(); constr = ((StackConstraints) constraints).layoutConstraints; setLayer(comp, layer); } else { layer = getLayer(comp); constr = constraints; } pos = insertIndexForLayer(layer, index); super.addImpl(comp, constraints, pos); comp.validate(); comp.repaint(); validateOptimizedDrawing(); 

}

因此,LayoutManager负责设置堆栈中所有组件的X坐标和Y坐标。 另一方面,JLayeredPane负责其Z坐标(通过其层)。

您不需要为此使用分层窗格。 面板还支持Z-Order。 查看重叠布局 ,它可以解释更多相关信息,并可以满足您的需求。