4

情况:抽一堆纸牌,就像纸牌游戏一样。叠得很漂亮。

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

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

向 a 添加组件JLayeredPane如下所示:

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

new Integer(j)卡的层在哪里。这一定是Integer由于合同的原因JLayeredPane

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

addLayoutComponent(Component comp, Object constraints);

并且传递的Object将永远是一个Integer.

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

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

4

2 回答 2

3

根据 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应该放置的层。然后,它将constraintsInteger 传递给超级实现。超级实现中的基本部分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)方法,该方法可以接受您选择的任何对象:该对象应包含IntegerJLayeredPane 层决策所需的内容,并且还应包含所选 LayoutManager 的约束对象。

堆栈约束:

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

}

于 2013-08-20T14:37:00.823 回答
2

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

您不需要为此使用分层窗格。面板还支持 Z-Order。查看重叠布局,其中解释了更多关于此的内容,并且可以满足您的需要。

于 2013-08-20T14:51:26.753 回答