2013-08-20 2 views
3

상황 : Solitaire 게임 에서처럼 카드 더미를 그립니다. 멋지게 쌓인.LayoutManager를 사용하는 JLayeredPane

이것을 달성하려면 을 LayoutManager 인터페이스의 맞춤 구현과 함께 사용하고 있습니다. 커스텀 LayoutManager를 사용하는 이유는 스택의 방향이 다양하기 때문에 때로는 부분적으로 카드가 서로 완전히 가끔씩 부분적으로 가려지기 때문입니다.이 로직은 LayoutManager에있어 좋은 역할을하는 것처럼 보입니다. 카드.

따라서 LayoutManager은 내 스택의 모든 구성 요소의 X 좌표 및 Y 좌표를 설정합니다. 반면에 JLayeredPane은 레이어를 통해 Z- 좌표를 담당합니다. JLayeredPane에 구성 요소를 추가

이렇게되면 : new Integer(j) 카드의 계층입니다

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

. JLayeredPane 계약으로 인해 Integer이어야합니다.

여기서의 문제는 위에서 설명한 이유 때문에 내 StackLayoutInteger 이외의 다른 제약 조건 개체를 사용할 수 없다는 것입니다.

addLayoutComponent(Component comp, Object constraints); 

및 전달 Object 여기에 항상 Integer 할 : LayoutManager 인터페이스는 다음과 같은 방법을 구현하는 방법이 필요합니다.

내 특정 상황에서 XY 좌표는 Z 좌표를 기반으로 계산할 수 있으므로 행운입니다. 예를 들어, 레이어 k의 카드는 Y 좌표 k * offset에 있어야합니다. 따라서 제 상황에서는 Integer 인 제약 객체가 문제가되지 않습니다.

Z 좌표와 XY 좌표 사이에 상관 관계가 없을 때 무엇을해야하는지 궁금합니다. 이 문제를 어떻게 풀 수 있습니까? 예를 들어 GridBagLayoutJLayeredPane과 함께 사용하려면 어떻게해야합니까? 첫 번째 기기는 GridBagConstraints이고 두 번째 기기는 Integer 개체가 필요합니까? 물론, GBL은 구성 요소가 겹치지 않는 방식으로 레이아웃을 작성하지만 아이디어 일뿐입니다.

+1

기본 동작을 변경해야하므로 JLayeredPane 확장에 대해 생각해 보셨습니까? 이 방법으로, JLayeredPane super에 필요한 Integer와 GridBagLayout 또는 비슷한 것을 사용하는 GridBagConstraints를 조합 한 고유 한 Object 제 2 매개 변수를 허용하는 자체 add 메소드를 작성할 수 있습니다. –

+0

@HovercraftFullOfEels 그것은 적절한 해결책이 될 것 같습니다. 'JLayeredPane'가 우선하는 protected void addImpl (Component comp, Object constraints, int index)를 오버라이드 (override) 할 필요가 있다고 생각합니다. 이것은, 층의 결정에 사용되는 Integer 오브젝트를 먼저 가로 채기 위해서 (때문에) 발생합니다. 다음에, 디폴트의'JLayeredPane'가 LayoutManager를 가지지 않기 때문에 궁극적으로 아무것도하지 않을 슈퍼 클래스 인 Container에 제약 조건을 전달합니다. 나는이 접근법에 대한 답을 쓸 것이다. – Timmos

답변

3

Hovercraft Full of Eels의 의견을 바탕으로, 나는 내 자신의 질문에 답할 것입니다.

JLayeredPane.add(Component comp, Object constraints) 전화는 addImpl(Component comp, Object constraints, int index)입니다. JLayeredPane의이 comp가 배치되어야하는 레이어를 알 수 있도록,

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 자체에 의해 무시되고, 여기에 소스입니다. 그런 다음, constraints 인 Integer를 수퍼 구현으로 전달합니다.슈퍼 구현의 필수적인 부분은, Container이며,이 객체가 Integer에 필요한 포함해야합니다

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) 메소드를 오버라이드 (override)하는 것 JLayeredPane의 계층 결정이며, 선택된 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(); 

}

+0

제안에 감사드립니다 (많은 도움이되었지만) 코드는 그대로 작동하지 않습니다. 1) layer = constraints.layer.intValue()는 ((StackConstraints) 제약 조건) .layer로 변경해야합니다. 2) constr의 형태가 Integer 인 경우 super.addImpl (...)은 레이어를 재설정합니다. 3) validateOptimizedDrawing()은 JLayeredPane의 private 메소드입니다. 하위 클래스에서 호출 할 수 없습니다. – Mischa

+0

다음은 대안입니다 : 'protected void addImpl (Component comp, Object constraints, int index) { \t \t int layer = 0; \t \t int pos = 0; \t \t Object constr; \t \t if (constraints instanceof StackConstraints) { \t \t \t layer = ((StackConstraints) 제약 조건). 레이어; \t \t \t constr = ((StackConstraints) 제약 조건).layoutConstraints; \t \t} else { \t \t \t layer = getLayer (comp); \t \t \t constr = constraints; \t \t \t \t pos = insertIndexForLayer (layer, index); \t \t super.addImpl (comp, constr, pos); \t \t setLayer (comp, layer, pos); \t \t comp.validate(); \t \t comp.repaint(); \t}' – Mischa

2

그래서, LayoutManager의 모든 구성 요소의 X 축과 Y 좌표를 설정하기위한 책임이 있습니다 내 스택. 한편, JLayeredPane는 그 레이어를 개입시켜 Z 좌표를 담당합니다.

이렇게하려면 계층화 된 창을 사용할 필요가 없습니다. 패널은 Z- 주문도 지원합니다. 이것에 대해 더 자세히 설명하고 필요한 것을 할 수있는 Overlap Layout을 확인하십시오.

+0

LM이 대부분의 게임에서 사용되지만 내 레이아웃은 완전히 벡터/상대적으로 정의됩니다. 따라서 선호하는 아동용 크기를 기준으로 부모 크기를 계산하지는 않지만 다른 방법으로 사용합니다. 따라서 적어도 하위 구성 요소의 기본/최소/최대 크기를 사용하는 LM이 최선의 선택이 될 수 없습니다. 귀하의 답변을 주셔서 감사 드리며, 프로젝트에서 사용할 수 있는지 조사하겠습니다. 그러나 문제는 대안에 관한 것이 아니라 JLayeredPane과 LayoutManager의 결합에 관한 것이 었습니다. JLayeredPane의 빌트인 겹침을 사용하지 않는 이유는 무엇입니까? – Timmos

+0

@Timmos,'대안은 JLayeredPane과 LayoutManager의 결합에 관한 것이 아니 었습니다 .' - 당신이 그 접근법에 대해 생각하지 않았을 수도 있고 새로운 아이디어를 줄 수도 있기 때문에 대안을 제시했습니다. 'JLayeredPane의 내장 레이어를 사용하지 않는 이유는 무엇입니까? '- 솔루션에는 JLayeredPane을 재정의하고 사용자 정의 레이아웃 관리자를 만드는 것이 포함됩니다. 내 제안은 내가 생각하기에 좀 더 깔끔한 레이아웃 관리자에 코드를 보관한다. 어쩌면 당신의 Vectorial 레이아웃 접근법과 내 ZOrder 접근법을 결합 할 수 있을까요? – camickr

관련 문제