2013-08-20 16 views
3

Ситуация: рисунок стопки игральных карт, как в игре Solitaire. Красиво сложены.JLayeredPane с LayoutManager

Для этого я использую JLayeredPane в сочетании с пользовательской реализацией интерфейса LayoutManager. Причина использования настраиваемого 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) представляет собой слой карты. Это должно быть Integer по договору JLayeredPane.

Проблема заключается в том, что у моего StackLayout не может быть другого объекта ограничения, кроме Integer, по причине, указанной выше. Интерфейс LayoutManager требует реализовать следующий метод:

addLayoutComponent(Component comp, Object constraints); 

и проходящее Object будет здесь всегда быть Integer.

В моей конкретной ситуации мне повезло, так как мои XY-координаты могут быть рассчитаны на основе Z-координат. Например, карта в слое k должна быть расположена в координате Y k * offset. Поэтому в моей ситуации объект ограничений, являющийся Integer, не является проблемой.

Мне было интересно, что вы должны делать, когда нет никакой корреляции между Z-координатами и XY-координатами? Как вы можете это решить? Например, как использовать GridBagLayout в сочетании с JLayeredPane, где первый требует объекта GridBagConstraints, а второй - объекта Integer? Конечно, GBL будет компоноваться таким образом, чтобы компоненты не перекрывались, но это всего лишь идея.

+1

Задумывались ли вы о расширении JLayeredPane, так как вам нужно изменить базовое поведение? Таким образом, вы можете создать свой собственный метод добавления, который позволил бы использовать свой собственный параметр Object 2nd, который объединил Integer, требуемый для суперпользователя JLayeredPane, и, возможно, GridBagConstraints, если макет использовал GridBagLayout или что-то подобное. –

+0

@HovercraftFullOfEels Кажется, что это может быть правильное решение. Я думаю, мне может потребоваться переопределить 'protected void addImpl (Component comp, Object constraints, int index)', который 'JLayeredPane' переопределяет сам, чтобы сначала перехватить объект Integer, который используется для определения слоя. Затем он передает ограничения на свой суперкласс «Контейнер», который в конечном итоге ничего не будет с ним делать, поскольку по умолчанию «JLayeredPane» не имеет LayoutManager. Я напишу ответ на этот подход. – Timmos

ответ

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 объект перехватывается, так что знает Панель со слоями слой, в котором 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), который может принять любой объект по своему выбору: этот объект должен содержать Integer, необходимые для решение уровня слоя 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; 
    } 
} 

Панель со слоями:

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. Вы не можете назвать это из подклассов. – Mischa

+0

Вот альтернатива: 'protected void addImpl (Component comp, Object constraints, int index) { \t \t int layer = 0; \t \t int pos = 0; \t \t Объект constr; \t \t, если (ограничения InstanceOf StackConstraints) { \t \t \t слой = ((StackConstraints) ограничения) .layer; \t \t \t constr = ((StackConstraints) ограничения).layoutConstraints; \t \t} else { \t \t layer = getLayer (comp); \t \t \t constr = ограничения; \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 отвечает за установление Х- и Y-координаты всех компонентов в моем стек. С другой стороны, JLayeredPane отвечает за их Z-координаты (через свои слои).

Для этого не нужно использовать слоистую панель. Панель также поддерживает Z-Order. Проверьте Overlap Layout, который объясняет больше об этом и может делать то, что вам нужно.

+0

Пока ваш LM будет делать для большинства игр, мой макет полностью векторный/относительно определен. Поэтому я не вычисляю размеры родителя на основе предпочтительных размеров детей, но наоборот. Таким образом, LM с использованием предпочтительных/минимальных/максимальных размеров дочерних компонентов не будет лучшим выбором, по крайней мере, в моем случае. Я ценю ваш ответ, хотя, я буду исследовать, могу ли я использовать его в своем проекте. Но вопрос был о комбинации JLayeredPane с LayoutManager, а не об альтернативах. Любая причина, по которой вы не будете использовать встроенную иерархию JLayeredPane? – Timmos

+0

@Timmos, вопрос был о комбинации JLayeredPane с LayoutManager, а не об альтернативах. - Я дал альтернативу, потому что вы, возможно, не подумали об этом, и это может дать вам новые идеи. 'Любая причина, по которой вы не будете использовать встроенную иерархию JLayeredPane?' - Ваше решение включает переопределение JLayeredPane и создание настраиваемого менеджера макетов. Мое предложение держит код только в менеджере компоновки, который, по моему мнению, более чист. Может быть, вы можете объединить свой подход Vectorial layout с моим подходом ZOrder? – camickr