JMenuItems painting over higher components in JLayeredPane

筅森魡賤 提交于 2019-12-06 08:01:09

问题


I have a set of JMenuItems in a JPanel on one layer of a JLayeredPane, and an emulated cursor painted in a JPanel on a higher layer. When the menu items repaint, they paint over the emulated cursor (without triggering a repaint of the cursor layer). Interestingly, if I substitute JButtons or JLabels for the menu items, the cursor is correctly painted each time the menu items repaint.

How can I ensure that repainting the menu items will cause the affected regions of the higher layers to repaint as well, without directly calling repaint() on the layered pane? The situation I've described is somewhat simplified from reality: the menu items may be deeply nested in a child of the layered pane, and they should not know about the layered pane at all.

Here's a snippet of pseudo-code illustrating what I've described:

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:


JComponent has a package-private alwaysOnTop() method that the Swing painting system uses to determine whether repainting a component may necessitate repainting other components. By default this method returns false, but JMenuItem overrides it to return true unless the menu item appears in a JInternalFrame. As a consequence, components that appear above a JMenuItem will not be repainted when the menu item is repainted (except when the menu item is in an internal frame).

Since alwaysOnTop() is package-private, it cannot be overridden in a custom component. It seems that the only solutions are to

  • use a different component (e.g. JButton, JLabel)
  • place the menu in an internal frame
  • make the components transparent (i.e. setOpaque(false))

I ended up using the latter solution. Since I didn't actually want transparent menu items I wrapped the paint code with calls to set/clear the opaque property:

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


来源:https://stackoverflow.com/questions/5668721/jmenuitems-painting-over-higher-components-in-jlayeredpane

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!