Swing: Как добиться пересылки всех событий из подкомпонентов в родительский контейнер? - PullRequest
2 голосов
/ 27 июня 2009

Я ищу простой способ сделать компонент Swing вперед всем полученным события для его родительского контейнера (или даже для всех родителей до root).

EDIT
Где мне это нужно? У меня есть редактор диаграмм. Компоненты должны переслать нажатие клавиши и щелчки мышью (чтобы установить себя как «активные», как только пользователь щелкает субэлемент этого компонента).

Во-первых, позвольте мне представить мое существующее решение для этого. Это что-то вроде обходного пути.

public interface IUiAction {
 void perform(Component c);
}

public static void performRecursiveUiAction(Container parent, IUiAction action) {
 if (parent == null) {
  return;
 }

 for (Component c : parent.getComponents()) {
  if (c != null) {
   action.perform(c);
  }
 }

 for (Component c : parent.getComponents()) {
  if (c instanceof Container) {
   performRecursiveUiAction((Container) c, action);
  }
 }
}

/**
* 1) Add listener to container and all existing components (recursively).
* 2) By adding a ContainerListener to container, ensure that all further added
* components will also get the desired listener.
*
* Useful example: Ensure that every component in the whole component
* tree will react on mouse click.
*/
public static void addPermanentListenerRecursively(Container container,
  final IUiAction adder) {

 final ContainerListener addingListener = new ContainerAdapter() {
  @Override
  public void componentAdded(ContainerEvent e) {
   adder.perform(e.getChild());
  }
 };

 // step 1)
 performRecursiveUiAction(container, adder);

 // step 2)
 performRecursiveUiAction(container, new IUiAction() {
  @Override
  public void perform(Component c) {
   if (c instanceof Container) {
    ((Container) c).addContainerListener(addingListener);
   }
  }
 });
}

Использование:

addPermanentListenerRecursively(someContainer,
  new IUiAction(
    @Override
    public void perform(Component c){
      c.addMouseListener(somePermanentMouseListener);
    }
  )
);

Рассматривая код, вы бы сказали, что это хорошая концепция?
Проблема с моей нынешней концепцией: она пересылает только события, для которых слушатель был указан вручную.

Можете ли вы предложить лучший?

Ответы [ 3 ]

3 голосов
/ 27 июня 2009

Исходя из вашего сценария, у меня есть предложение для клавиатуры:

Вы можете использовать средство свинга KeyStroke для этого:

JRootPane rp = getRootPane();

KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0, false);
rp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ks, "F2");
rp.getActionMap().put("F2", new AbstractAction() { 
public void actionPerformed(ActionEvent e) { onF2Action(); } });

Таким образом, вы можете зарегистрировать «глобальные» обработчики событий для ярлыков 1 .

1 , хотя в вашем случае это может иметь некоторые ограничения.

Для случая события мыши я бы создал рекурсивную функцию, которая добавляет экземпляр MouseAdapter к каждому целевому компоненту. Например:

void addToAll(Container c, MouseAdapter a) {
    for (Component p : c.getComponents()) {
        if (p instanceof InterrestingComponent) {
            p.addMouseListener(a);
            p.addMouseMotionListener(a);
            p.addMouseWheelListener(a);
        } else
        if (p instanceof Container) {
            addToAll((Container)p, a);
        }
    }
}

Просто чтобы захватить концепцию. Вам могут потребоваться разные или несколько приемников для различных компонентов.

Редактировать: Извините, я случайно сказал WindowAdapter вместо MouseAdapter.

2 голосов
/ 27 июня 2009

Похоже, было бы немного сложно, если бы каждый компонент в вашем представлении обрабатывал одно и то же событие мыши. то есть, если пользователь перетаскивает item 1 , item 2 , будут ли также обрабатываться эти события? если я правильно понимаю, вы хотите, чтобы this и this.parent и this.parent.parent обрабатывали действия мыши на this. в этом случае рекурсия будет вверх, а не вниз.

вы можете создать Interface, например:

public interface MyInterface() {
   public void performSpecialAction(Event event);
}

тогда ваши контейнеры реализуют этот интерфейс. тогда ваши компоненты должны будут включить этот вызов в соответствующую обработку событий:

public static void performRecursiveUiAction(Component comp, Event event) {
  if (comp.getParent() == null) {
     return;
  }
  if (comp.getParent() instanceof MyInteface) {
     ((MyInterface)comp.getParent()).performSpecialAction(event);
  }
  ThisUtility.performRecursiveUiAction(comp.getParent(), event);

}

1 голос
/ 22 октября 2011
  • Либо вы получаете события от компонентов, и в этом случае вы регистрируете слушателей, где вам нужно захватывать события. Преимущество заключается в том, что вы можете выбрать, где захватывать события, и у вас есть выбор, чтобы получать их выборочно по источникам. Дело в том, что вы должны зарегистрировать столько слушателей, сколько у вас есть источника ...
  • Или используйте стеклянную панель и захватите все, прежде чем она распространится на компоненты. В этом случае вы фиксируете их все, и вы должны написать собственный код обработки, если хотите связать их с компонентами под стеклянной панелью. (Предполагая, что вы сохранили стеклянную панель пустой ...) Вот пример, который фиксирует события до того, как они достигнут компонентов, и даже перенаправляет их выбранным: http://download.oracle.com/javase/tutorial/uiswing/components/rootpane.html#glasspane
  • Срединная цель - использовать многослойную панель для создания прозрачных компонентов (подобных стеклам) над всем, что вам нужно.

Кроме того, вы также можете использовать события () ... Ваша главная проблема - компромисс, который вы либо захватываете события перед обработчиками свинга (и пишете пользовательскую обработку с нуля), либо после них (и имеете некоторые помехи от обработки, которая у вас может быть) взломать), но вы не можете изменить сам код обработки, подклассифицировав что-либо (или можете? никогда не видели до сих пор ...).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...