Client Menu Bar icon visibility

Is there a way with the Client Menu Bar to hide and show the icon for the individual item?
In this case, I want a checkbox icon to only be visible if the state of a boolean tag is true.

I believe there is, but its a little tricky and unsupported by IA. I don’t have full code or anything but I can give you an idea of how to do this. I’d suggest something in the client startup script that will use java’s SwingUtilities.getRoot() method to get the top jframe. You might have to do some exploration with .getComponents() from there to find the menu bar object, but once you find that you can navigate the menu bar, find this item, and change the icon from there.

Hope that makes sense and helps get you started. I do have a small project doing nearly this (disabling menu options based on client tags) so I’ll update this if I have any better code.

Edit:
Here’s how I found the JMenu items you’ll need to modify -

	from javax.swing import SwingUtilities
		
	ws = list(SwingUtilities.getRoot(self).getWindows())

	realRoot = [x for x in ws if 'javax.swing.JFrame' in str(x) and x.getTitle() != 'Launching'][0]
	
	tatext = []
	
	for x in realRoot.getComponents():
		tatext.append('%s' % str(x))
		for y in x.getComponents():
			tatext.append('   %s' % str(y))
			try:
				for z in y.getComponents():
					tatext.append('      %s' % str(z))
					
					try:
						for w in z.getComponents():
							tatext.append('         %s' % str(w))
					except:
						pass
			except:
				pass
				
				
	tatext += ['' for x in range(5)]
	
	self.parent.getComponent('Text Area').text =  '\n'.join(tatext)

This is in a dummy testing window that has a button (where this script is run), and a Text Area component for debugging. Not the cleanest code, but that can be fixed later. Run it in the client and it should give some results like this:

javax.swing.JRootPane[,8,30,2560x1418,layout=com.incors.plaf.alloy.bk,alignmentX=0.0,alignmentY=0.0,border=,flags=16777673,maximumSize=,minimumSize=,preferredSize=]
   com.inductiveautomation.factorypmi.application.runtime.LayeredGlassPane[,0,0,2560x1418,hidden,layout=com.inductiveautomation.factorypmi.application.runtime.LayeredGlassPane$1,alignmentX=0.0,alignmentY=0.0,border=,flags=0,maximumSize=,minimumSize=,preferredSize=,optimizedDrawingPossible=true]
   javax.swing.JLayeredPane[null.layeredPane,0,0,2560x1418,alignmentX=0.0,alignmentY=0.0,border=,flags=0,maximumSize=,minimumSize=,preferredSize=,optimizedDrawingPossible=true]
      com.inductiveautomation.factorypmi.application.runtime.ClientPanel[,0,23,2560x1395,layout=java.awt.BorderLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=]
         com.inductiveautomation.factorypmi.application.runtime.ClientPanel$NorthPane[,0,0,2560x0,layout=java.awt.GridLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=]
         javax.swing.JScrollPane[,0,0,2560x1370,layout=javax.swing.ScrollPaneLayout$UIResource,alignmentX=0.0,alignmentY=0.0,border=com.incors.plaf.alloy.cz@170b7405,flags=328,maximumSize=,minimumSize=,preferredSize=,columnHeader=,horizontalScrollBar=javax.swing.JScrollPane$ScrollBar[,0,0,0x0,hidden,layout=com.incors.plaf.alloy.AlloyScrollBarUI,alignmentX=0.0,alignmentY=0.0,border=javax.swing.plaf.BorderUIResource$EmptyBorderUIResource@625866ef,flags=4194664,maximumSize=,minimumSize=,preferredSize=,blockIncrement=10,orientation=HORIZONTAL,unitIncrement=1],horizontalScrollBarPolicy=HORIZONTAL_SCROLLBAR_AS_NEEDED,lowerLeft=,lowerRight=,rowHeader=,upperLeft=,upperRight=,verticalScrollBar=javax.swing.JScrollPane$ScrollBar[,2543,2,15x1345,hidden,layout=com.incors.plaf.alloy.AlloyScrollBarUI,alignmentX=0.0,alignmentY=0.0,border=javax.swing.plaf.BorderUIResource$EmptyBorderUIResource@625866ef,flags=4194664,maximumSize=,minimumSize=,preferredSize=,blockIncrement=10,orientation=VERTICAL,unitIncrement=1],verticalScrollBarPolicy=VERTICAL_SCROLLBAR_AS_NEEDED,viewport=javax.swing.JViewport[,2,2,2556x1366,layout=javax.swing.ViewportLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=25165832,maximumSize=,minimumSize=,preferredSize=,isViewSizeSet=true,lastPaintPosition=java.awt.Point[x=0,y=0],scrollUnderway=false],viewportBorder=]
         com.inductiveautomation.factorypmi.application.runtime.TrialBar[,0,1370,2560x25,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=16777225,maximumSize=,minimumSize=,preferredSize=]
      com.inductiveautomation.factorypmi.application.runtime.RuntimeMenu[,0,0,2560x23,layout=javax.swing.plaf.basic.DefaultMenuLayout,alignmentX=0.0,alignmentY=0.0,border=javax.swing.plaf.BorderUIResource@3fc3453a,flags=392,maximumSize=,minimumSize=,preferredSize=,margin=,paintBorder=true]
         javax.swing.JMenu[,0,1,73x21,alignmentX=0.0,alignmentY=0.0,border=com.incors.plaf.alloy.cy@70713c37,flags=392,maximumSize=,minimumSize=,preferredSize=,defaultIcon=,disabledIcon=,disabledSelectedIcon=,margin=javax.swing.plaf.InsetsUIResource[top=2,left=2,bottom=2,right=2],paintBorder=true,paintFocus=false,pressedIcon=,rolloverEnabled=false,rolloverIcon=,rolloverSelectedIcon=,selectedIcon=,text=Command]
         javax.swing.JMenu[,73,1,73x21,alignmentX=0.0,alignmentY=0.0,border=com.incors.plaf.alloy.cy@70713c37,flags=264,maximumSize=,minimumSize=,preferredSize=,defaultIcon=,disabledIcon=,disabledSelectedIcon=,margin=javax.swing.plaf.InsetsUIResource[top=2,left=2,bottom=2,right=2],paintBorder=true,paintFocus=false,pressedIcon=,rolloverEnabled=false,rolloverIcon=,rolloverSelectedIcon=,selectedIcon=,text=Test Menu]
         com.inductiveautomation.factorypmi.application.WindowsMenu[,146,1,67x21,alignmentX=0.0,alignmentY=0.0,border=com.incors.plaf.alloy.cy@70713c37,flags=264,maximumSize=,minimumSize=,preferredSize=,defaultIcon=,disabledIcon=,disabledSelectedIcon=,margin=javax.swing.plaf.InsetsUIResource[top=2,left=2,bottom=2,right=2],paintBorder=true,paintFocus=false,pressedIcon=,rolloverEnabled=false,rolloverIcon=,rolloverSelectedIcon=,selectedIcon=,text=Windows]
         javax.swing.JMenu[,213,1,39x21,alignmentX=0.0,alignmentY=0.0,border=com.incors.plaf.alloy.cy@70713c37,flags=392,maximumSize=,minimumSize=,preferredSize=,defaultIcon=,disabledIcon=,disabledSelectedIcon=,margin=javax.swing.plaf.InsetsUIResource[top=2,left=2,bottom=2,right=2],paintBorder=true,paintFocus=false,pressedIcon=,rolloverEnabled=false,rolloverIcon=,rolloverSelectedIcon=,selectedIcon=,text=Help]

Then you can find the actual one you want by getting the text of each menu, then use getComponents() on that to find the menu item you want.

As noted by @mrogers, you can do this by manually editing the app menu on startup. Instead of doing so on every change to the checkbox, just insert a JCheckBoxMenuItem. (-:

2 Likes

Okay, so then I would be including the following in my startup script:

from javax.swing import JCheckBoxMenuItem

I see that JCheckBoxMenuItem creates a new checkbox option. Would I need to recreate the menu in the startup script instead of the menubar toolset?