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

#java #swing #jlayeredpane #jmenuitem

#java #swing #jlayeredpane #jmenuitem

Вопрос:

У меня есть набор 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);
}
  

Комментарии:

1. Хорошо, но, пожалуйста, уточните, в чем вопрос. 🙂 Плюс код был бы полезен, чтобы увидеть все, что вы имеете в виду.

Ответ №1:

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

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

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

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

 @Override
protected void paintComponent(Graphics g)
{ 
   // paint the component as opaque
   setOpaque(true);
   super.paintComponent(g);
   setOpaque(false);
}
  

Комментарии:

1. 1 Хорошо, что вы поделились с нами своим решением вашей проблемы. Это решение, с которым я бы согласился.