Just for fun, I went ahead and worked out what the color adjustment is for the selected sub menus. In all cases, the red value is reduced to 84% of the initial value; the green value is reduced to 93% of its initial value, and the blue value isn't changed at all. This effect can't be seen in my original example because I was using pure black, so the RGB values were all 0.
To eliminate the shading, the menu item and submenu background colors have to be defined separately:
# Initial RGB values for the background color
# [MUST BE values between 0 and 255]
red = 255
green = 255
blue = 255
# Define the sub menu background color using the initial RGB values,
# ...and adjust the menuItem background color to match what the submenu background will be after selected is set to True
subMenuBGColor = system.gui.color(red, green, blue)
menuItemBGColor = system.gui.color(int(red * 0.84), int(green * 0.93), blue)
Then, distinguish the two in the mouse adapter:
def mouseExited(self, event):
self.originalListener.mouseExited(event)
if 'JySubMenu' in event.source.__class__.__name__:
event.source.background = subMenuBGColor
else:
event.source.background = menuItemBGColor
# [...]
def restoreSelections(self, event):
for component in event.source.parent.components:
if 'JySubMenu' in component.__class__.__name__:
component.selected = True
else:
component.background = menuItemBGColor
...and in the setMenuColor
function:
if 'JySubMenu' in component.__class__.__name__:
setMenuColor(component, subMenuBGColor, foregroundColor)
setMenuColor(component.popupMenu, subMenuBGColor, foregroundColor)
component.selected = True
else:
setMenuColor(component, menuItemBGColor, foregroundColor)
Here is the updated code example with the changes applied:
Complete Code Example
# Using the mouseReleased event handler
# Create a listner that reapplies the selected property of all JySubMenu items
# ...after the BasicMenuUI listener has done all of its required work
from java.awt.event import MouseAdapter
class NonDeselectingListener(MouseAdapter):
def __init__(self, originalListener):
self.originalListener = originalListener
def mouseEntered(self, event):
self.originalListener.mouseEntered(event)
self.restoreSelections(event)
event.source.background = highlightColor
def mouseExited(self, event):
self.originalListener.mouseExited(event)
if 'JySubMenu' in event.source.__class__.__name__:
event.source.background = subMenuBGColor
else:
event.source.background = menuItemBGColor
def mouseReleased(self, event):
self.originalListener.mouseReleased(event)
def restoreSelections(self, event):
for component in event.source.parent.components:
if 'JySubMenu' in component.__class__.__name__:
component.selected = True
else:
component.background = menuItemBGColor
# Recursively sets the background and foreground colors of all the sub components of a popup menu
def setMenuColor(menu, background, foreground):
menu.background = background
menu.foreground = foreground
for component in menu.components:
# If a submenu is found, color its popup and set it selected property to true
if 'JySubMenu' in component.__class__.__name__:
setMenuColor(component, subMenuBGColor, foregroundColor)
setMenuColor(component.popupMenu, subMenuBGColor, foregroundColor)
component.selected = True
else:
setMenuColor(component, menuItemBGColor, foregroundColor)
# Locate the Basic UI listener of the menu item
# ...and wrap in a listener that listener that will restore the selected coloring
# ...before the component is repainted
for listener in component.mouseListeners:
if 'BasicMenuUI' in listener.__class__.__name__ or 'BasicMenuItemUI' in listener.__class__.__name__:
component.removeMouseListener(listener)
component.addMouseListener(NonDeselectingListener(listener))
# Simple nested popup example based on documented example # 4:
def sayHello(event):
print 'Hello'
highlightColor = system.gui.color('red')
# Initial RGB values for the background color
# [MUST BE values between 0 and 255]
red = 96
green = 96
blue =96
subMenuBGColor = system.gui.color(red, green, blue)
# Match color with selected color
menuItemBGColor = system.gui.color(int(red * 0.84), int(green * 0.93), blue)
foregroundColor = system.gui.color('white')
subMenu01 = [["Click Me 1", "Click Me 2"], [sayHello, sayHello]]
subMenu02 = [["Click Me 3", "Click Me 4"], [sayHello, sayHello]]
subMenu03 = [["Click Me 5", "Click Me 6"], [sayHello, sayHello]]
subMenu04 = [["Click Me 7", "Click Me 8"], [sayHello, sayHello]]
subMenu05 = [["Click Me 9", "Click Me 10"], [sayHello, sayHello]]
menu = system.gui.createPopupMenu(['Click Me', 'subMenu01', 'Click Me', 'subMenu03', 'Click Me', 'subMenu05'], [sayHello, subMenu01, sayHello, subMenu03, sayHello, subMenu05])
setMenuColor(menu, menuItemBGColor, foregroundColor)
menu.focusable = False
menu.show(event)
When using the code example above, the menu item color will always match the selected sub menu color no matter what initial RGB values are assigned to the red, green, and blue variables.
Result:
Edit: Added additional details and improved mouse adaptor handling