JMenuItems painting over higher components in JLayeredPane
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);
}开发者_如何学JAVA
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);
}
精彩评论