# Jython: Setting up a Popup Menu dynamically

**URL:** <https://forum.inductiveautomation.com/t/jython-setting-up-a-popup-menu-dynamically/6318>\
**Category:** Ignition\
**Created:** [April 24, 2013, 7:40pm UTC](https://forum.inductiveautomation.com/t/jython-setting-up-a-popup-menu-dynamically/6318 "2013-04-24T19:40:57Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![karnick](https://avatars.discourse-cdn.com/v4/letter/k/c37758/32.png) [@karnick](https://forum.inductiveautomation.com/u/karnick)\
**Post date:** [April 24, 2013, 7:40pm UTC](https://forum.inductiveautomation.com/t/jython-setting-up-a-popup-menu-dynamically/6318/1 "2013-04-24T19:40:57Z")

</div>

I am having some trouble on the Jython end of creating a popup menu. The underlying goal (while perhaps not the best programming practice) is to have each item’s action perform a Jython command which is stored as a string in the database. I have a function called ‘generalFunction’ which is supposed to retrieve a string from the database depending on which item was selected. The problem is that when I setup the dictionary sequence to populate the popup (in the format of {‘Menu Text’:functionToCall} ) I cannot pass a parameter into my functionToCall (in my case it is generalFunction). If I define the action for the item to be generalFunction(idx), the function executes immediately which I do not want. I just want to assign a different instance of this function to each item in the popup menu.

Is there anyway to setup a function that can reference another function as a variable? Would I be better off going about this at the Java level and using the Java JMenuPopup documentation? Thanks in advance!

[code]qryText = “SELECT idx, popupText FROM %s WHERE id = %i AND roleId =%i” %(popupCfgTable, depth, roleId)   
popupData = system.db.runQuery(qryText, dbname)

def generalFunction(idx=idx, event=event, selectedId=selectedId, selectedParentId=selectedParentId, popupCfgTable=popupCfgTable, depth=depth):   
import system  
import app  
qryNames = “SELECT functionName FROM %s WHERE idx = %i” %(popupCfgTable, idx)  
functionName = system.db.runScalarQuery(qryNames, dbname)  
exec functionName

# Obtain the unique id and popup message text based on the depth of the selection and the user’s role

popSequence = {}  
for p in popupData:  
idx = p[0]  
popupText = p[1]   
popSequence[popupText] = generalFunction

# popSequence[popupText] = generalFunction(idx)

menu = system.gui.createPopupMenu(popSequence)   
menu.show(event)[/code]

---

<div class="post-metadata">

**Author:** ![adamaustin](https://avatars.discourse-cdn.com/v4/letter/a/5f8ce5/32.png) [@adamaustin](https://forum.inductiveautomation.com/u/adamaustin)\
**Post date:** [April 24, 2013, 9:20pm UTC](https://forum.inductiveautomation.com/t/jython-setting-up-a-popup-menu-dynamically/6318/2 "2013-04-24T21:20:59Z")

</div>

You could use the eval function to make dynamic function calls from strings.

Here’s a test case I created:

Create a Script Module (app.popupmenu):

```auto
def testMyFunction(TextToDisplay):
	import system
	system.gui.messageBox(TextToDisplay)

def callIt(myFunc):
	import app
	eval(myFunc + "(\"Hello, World\")")
```

Create a window and add a button (Root Container.Button).  
Right click the button and go to Event Handlers.  
On left, click + by action then click actionPerformed.  
Click tab Script Editor:

```auto
app.popupmenu.callIt("app.popupmenu.testMyFunction")
```

Click OK.  
Click the green PREVIEW arrow (see attached image).  
Click BUTTON.

See “Hello, World”  
 ![](https://us1.discourse-cdn.com/inductiveautomation/original/2X/2/2ea299beb0f04a4107c191eca22eeba7aac2b229.jpg)

---

<div class="post-metadata">

**Author:** ![karnick](https://avatars.discourse-cdn.com/v4/letter/k/c37758/32.png) [@karnick](https://forum.inductiveautomation.com/u/karnick)\
**Post date:** [April 24, 2013, 10:22pm UTC](https://forum.inductiveautomation.com/t/jython-setting-up-a-popup-menu-dynamically/6318/3 "2013-04-24T22:22:54Z")

</div>

[quote=“adamaustin”]You could use the eval function to make dynamic function calls from strings.

Here’s a test case I created:

Create a Script Module (app.popupmenu):

```auto
def testMyFunction(TextToDisplay):
	import system
	system.gui.messageBox(TextToDisplay)

def callIt(myFunc):
	import app
	eval(myFunc + "(\"Hello, World\")")
```

Create a window and add a button (Root Container.Button).  
Right click the button and go to Event Handlers.  
On left, click + by action then click actionPerformed.  
Click tab Script Editor:

```auto
app.popupmenu.callIt("app.popupmenu.testMyFunction")
```

Click OK.  
Click the green PREVIEW arrow (see attached image).  
Click BUTTON.

See “Hello, World”[/quote]

Thanks for the reply. Unfortunately using eval yielded the same results. The function gets executed immediately.

I’ve also tried using “lambda” to create an anonymous function that calls my generalFunction function but when I do that the generalFunction goes out of scope (error says that function isn’t defined).

I’ve been reading up on callback functions but haven’t found any that give a clear example as to what is going on.

---

<div class="post-metadata">

**Author:** ![Carl.Gould](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/carl.gould/32/7262_2.png) [@Carl.Gould](https://forum.inductiveautomation.com/u/Carl.Gould)\
**Post date:** [April 24, 2013, 11:06pm UTC](https://forum.inductiveautomation.com/t/jython-setting-up-a-popup-menu-dynamically/6318/4 "2013-04-24T23:06:45Z")

</div>

For now you can just move the “def” of the general function (with idx=idx) inside the loop so it gets redefined for each unique index.

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [April 24, 2013, 11:07pm UTC](https://forum.inductiveautomation.com/t/jython-setting-up-a-popup-menu-dynamically/6318/5 "2013-04-24T23:07:50Z")

</div>

Well, I know this doesn’t exactly help you now, but in 7.6 you’ll be able to do something like this:

```auto
from functools import partial

def f1(event):
	print 'f1(event=%s)' % str(event)
	
def f2(event):
	print 'f2(event=%s)' % str(event)

def f3(event, param):
	print 'f3(event=%s, param=%s)' % (str(event), str(param))
	 
	 
f3_partial = partial(f3, param='some value')

menu = system.gui.createPopupMenu({
	'item1' : f1, 
	'item2' : f2, 
	'item3' : f3_partial})
	
menu.show(event)
```

This is valid Jython code in 7.5 as well, but because of some internal scripting details it won’t work for this particular case.

---

<div class="post-metadata">

**Author:** ![karnick](https://avatars.discourse-cdn.com/v4/letter/k/c37758/32.png) [@karnick](https://forum.inductiveautomation.com/u/karnick)\
**Post date:** [April 24, 2013, 11:22pm UTC](https://forum.inductiveautomation.com/t/jython-setting-up-a-popup-menu-dynamically/6318/6 "2013-04-24T23:22:42Z")

</div>

Thanks Carl I think I may try that. I actually originally came back to this thread to post a solution I found. Essentially I globally stored the DB table’s unique column (idx) and the function to be called when a popup is clicked (generalFunction). Wasn’t too thrilled about this solution, but it works.

[code]qryText = “SELECT idx, popupText FROM %s WHERE id = %i AND roleId =%i” %(popupCfgTable, depth, roleId)   
popupData = system.db.runQuery(qryText, dbname)   
for p in popupData:  
idx = p[0]  
popupText = p[1]   
#system.gui.messageBox(“idx=%i” %(idx))

def generalFunction(idx, event=event, selectedId=selectedId, selectedParentId=selectedParentId, popupCfgTable=popupCfgTable, depth=depth):   
import system  
import system  
import app  
# Obtain the function to be called from the database, looked up by unique id (idx).  
qryNames = “SELECT functionName FROM %s WHERE idx = %i” %(popupCfgTable, idx)  
functionName = system.db.runScalarQuery(qryNames, dbname)   
# Call the command obtained from the DB  
exec functionName

# Prepare the dictionary for the popup configuration

popSequence = {}

# Setup horrible solution of using global variables

global tmp\_lambda  
global tmp\_gf  
tmp\_lambda = 0

# Populate the dictionary and setup calls to generalFunction

for p in popupData:  
idx = p[0]  
popupText = p[1]   
tmp\_idx = idx  
tmp\_gf = generalFunction  
gf = lambda x : tmp\_gf(tmp\_idx)  
popSequence[popupText] = gf

menu = system.gui.createPopupMenu(popSequence)   
menu.show(event)

[/code]

Nothing like putting a band-aid on the problem.

---

<div class="post-metadata">

**Author:** ![karnick](https://avatars.discourse-cdn.com/v4/letter/k/c37758/32.png) [@karnick](https://forum.inductiveautomation.com/u/karnick)\
**Post date:** [April 25, 2013, 5:29pm UTC](https://forum.inductiveautomation.com/t/jython-setting-up-a-popup-menu-dynamically/6318/7 "2013-04-25T17:29:25Z")

</div>

Just an update, the above solution did not work. All the parameters for the function seemed to be passed by reference rather than value. The solution was to actually add a callback function. I also noticed a bug where the callback function required the event to be the first parameter. I’m not sure why and it thew me through a loop for a while. I also had to use ‘eval’ instead of ‘exec’ since you are apparently not allowed to use exec inside a callback that uses ‘free variables’.

Long story short, this works:

[code]qryText = “SELECT idx, popupText FROM %s WHERE id = %i AND roleId =%i ORDER BY idx ASC” %(popupCfgTable, depth, roleId)  
popupData = system.db.runQuery(qryText, dbname)  
for p in popupData:  
idx = p[0]  
popupText = p[1]

def generalFunction(event,idx, selectedId , selectedParentId, depth, popupCfgTable):  
import system  
import system  
import app

```
def callback(event, idx=idx, selectedId=selectedId , selectedParentId=selectedParentId, depth=depth, popupCfgTable=popupCfgTable):
	import app
	import system

	qryNames = "SELECT functionName FROM %s WHERE idx = %i " %(popupCfgTable, idx)
	functionName = system.db.runScalarQuery(qryNames, dbname)      
	eval(functionName)
									
return callback		  

```

# Prepare the dictionary for the popup configuration

popSequence = {}

for p in popupData:  
idx = p[0]  
popupText = p[1]  
gf = generalFunction(event, idx, selectedId , selectedParentId, depth, popupCfgTable)  
popSequence[popupText] = gf

# Create and show the popup

menu = system.gui.createPopupMenu(popSequence)  
menu.show(event)

[/code]

Looking forward to 7.6’s support of the partial package.

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [April 25, 2013, 6:35pm UTC](https://forum.inductiveautomation.com/t/jython-setting-up-a-popup-menu-dynamically/6318/8 "2013-04-25T18:35:54Z")

</div>

7.5 supports partial() too, but the createPopupMenu() function doesn’t know how to call the object returned by partial() in 7.5.

Feel free to use it in other places, if appropriate, though.
