JMenuItems прорисовывает более высокие компоненты в JLayeredPane

У меня есть набор JMenuItems в JPanel на одном слое JLayeredPane и эмулируемый курсор, нарисованный в JPanel на более высоком уровне. Когда элементы меню перерисовываются, они закрашивают эмулируемый курсор (без запуска перерисовки слоя курсора). Интересно, что если я заменю JButtons или JLabels для пунктов меню, курсор правильно рисуется каждый раз, когда пункты меню перерисовываются.

Как я могу гарантировать, что перерисовка пунктов меню вызовет перерисовку затронутых областей более высоких слоев, без прямого вызова repaint() на многоуровневой панели? Описанная мной ситуация несколько упрощена. из реальности: пункты меню могут быть глубоко вложены в дочерний элемент многоуровневой панели, и они вообще не должны знать о многоуровневой панели.

Вот фрагмент псевдокода, иллюстрирующий то, что я описал:

public void initGui(Dimension size) {
   JLayeredPane layeredPane = new JLayeredPane();
   layeredPane.setSize(size);

   menuPanel = new JPanel();
   menuPanel.setSize(size);
   layeredPane.add(menuPanel, BOTTOM_LAYER);

   JPanel cursorPanel = new CursorPanel();
   cursorPanel.setSize(size);
   layeredPane.add(cursorPanel, TOP_LAYER);
}

public void showMenu(Component[] menuItems) {
   JPanel menu = new JPanel();
   for (Component c: menuItems)
      menu.add(c);
   menuPanel.add(menu);
}

person Aaron Novstrup    schedule 14.04.2011    source источник
comment
Хорошо, но, пожалуйста, уточните, в чем вопрос. :) Плюс код был бы полезен, чтобы увидеть все, что вы имеете в виду.   -  person Boro    schedule 14.04.2011


Ответы (1)


JComponent имеет собственный пакетный метод alwaysOnTop(), который система рисования Swing использует для определения того, может ли перерисовка компонента потребовать перерисовки других компонентов. По умолчанию этот метод возвращает false, но JMenuItem переопределяет его, возвращая true, если только пункт меню не появляется в JInternalFrame. Как следствие, компоненты, которые появляются над JMenuItem, не будут перерисовываться при перерисовке пункта меню (кроме случаев, когда пункт меню находится во внутреннем фрейме).

Поскольку alwaysOnTop() является частным пакетом, его нельзя переопределить в пользовательском компоненте. Кажется, что единственными решениями являются

  • использовать другой компонент (например, JButton, JLabel)
  • поместить меню во внутреннюю рамку
  • сделать компоненты прозрачными (т.е. setOpaque(false))

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

@Override
protected void paintComponent(Graphics g)
{ 
   // paint the component as opaque
   setOpaque(true);
   super.paintComponent(g);
   setOpaque(false);
}
person Aaron Novstrup    schedule 14.04.2011
comment
+1 Хорошо, что вы поделились с нами решением своей проблемы. Это решение, с которым я бы согласился. - person Boro; 15.04.2011