LinuxQuestions.org
Review your favorite Linux distribution.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Software
User Name
Password
Linux - Software This forum is for Software issues.
Having a problem installing a new program? Want to know which application is best for the job? Post your question in this forum.

Notices


Reply
  Search this Thread
Old 08-12-2020, 06:06 AM   #1
KlaasJan
LQ Newbie
 
Registered: Aug 2006
Posts: 28

Rep: Reputation: 0
Tkinter menu: trying to use item label in callback


Hello,
In a tkinter app I have a two-level menu with book categories, like Exact - Astronomy
or Music - Classic. The second level is added to the first one with add_cascade.
I want to use the labels of any duo in the appropriate command-callback, without writing them litterally in the callback. So far in my experiments I allways get back the labels of the last duo fed into the gui. I do understand now why. But how to get the labels I clicked on ?
KlaasJan
 
Old 08-12-2020, 09:13 AM   #2
smallpond
Senior Member
 
Registered: Feb 2011
Location: Massachusetts, USA
Distribution: Fedora
Posts: 4,147

Rep: Reputation: 1264Reputation: 1264Reputation: 1264Reputation: 1264Reputation: 1264Reputation: 1264Reputation: 1264Reputation: 1264Reputation: 1264
Could you show the code you are trying? One way to pass an argument to a common callback is by using a lambda:
Code:
def myCallback(label):
    print "You clicked on",label 

menubar.add_command(label="Hello", command=lambda: myCallback("Hello"))
 
Old 08-12-2020, 11:07 AM   #3
KlaasJan
LQ Newbie
 
Registered: Aug 2006
Posts: 28

Original Poster
Rep: Reputation: 0
Tkinter menu: trying to use item label in callback

Thanks for looking at my problem.
I had to translate my script from dutch into my english.
My difficulty is with the dictionary self.rubmap{},
in which each self.rubmap[mainLabel] refers to a menu for this main-label,
and to which are added the sub-labels, each with a command-option.
The script:

#!/usr/bin/env python3

from tkinter import *
from tkinter.ttk import *

class UniMenu():
def __init__(self,root):
self.root = root
geometrie = "800x50+600+200"
self.root.geometry(geometrie)
self.rubric = Label(self.root,text='Rubric:')
self.rubric.pack(side=LEFT)

# make a menu-bar for one item only:
self.uMenu = Menu(self.root,type='menubar')

# fill het hele menu:
self.fillRubric()

# put the newly created rubMenu below uMenu:
self.uMenu.add_cascade(label='click',menu=self.rubMenu)

# display the completed uMenu
self.uMenu.pack(side=LEFT)

def fillRubric(self):
'''
Main-rubrics and sub-rubrics come from a file called 'afdeling',
which means rubric (!).
A part of it looks like this, an indented line is a sub-rubric:

Exact
Wiskunde_statistiek
Informatica
Natuurkunde
Astronomie
Geologie
Biologie
Mens
'''
def show(a,b):
print("Choice: %s: %s" % (a,b))

# maak een vooralsnog onzichtbaar sub-menu rubMenu:
rubricfile = "/kappa/data/afdeling"
self.rubMenu = Menu(self.uMenu,tearoff=0)
self.rubmap = {}
rf = open(rubricfile,'r')
mainRubCounter = 0
subRubCounter = 0
for fileLine in rf:
# a sub-rubric starts in the import-file with at least one space:
mainRubric = False if fileLine.startswith(" ") else True
self.shortLine = fileLine.strip()

if self.shortLine.startswith('#'): continue
if len(self.shortLine) < 1: continue

if mainRubric:

if mainRubCounter > 0:
# A main-rubric can only be cascaded when allof its subs are read,
# at least that is what I think how it works,
# so I made it a one-fase-off procedure.
self.rubMenu.add_cascade(label=self.mainLabel,menu=self.rubmap[self.mainLabel])
print("Menu: rubMenu Index: %s Label: %s" % (self.rubMenu.index(self.mainLabel), self.mainLabel))
self.mainLabel = self.shortLine
mainRubCounter += 1
self.rubmap[self.mainLabel] = Menu(self.rubMenu, tearoff=0)
else:
# command trial: lambda: show(self.mainLabel,self.shortLine))
z = lambda: show(self.mainLabel,self.shortLine)
self.rubmap[self.mainLabel].add_command(label=self.shortLine,command=z)
print("Menu: rubmap[%s] Index: %s Label: %s" % (self.mainLabel,
self.rubmap[self.mainLabel].index(self.shortLine), self.shortLine))
# De last mainRubric, because because mainRubric telkens een achterloopt:
self.rubMenu.add_cascade(label=self.mainLabel,menu=self.rubmap[self.mainLabel])
print("Menu: rubMenu Index: %s Label: %s" % (self.rubMenu.index(self.mainLabel), self.mainLabel))

def doNothing(self):
pass

root = Tk()
root.title('Experiment with a rubric tree')
um = UniMenu(root)
root.mainloop()


,
 
Old 08-12-2020, 11:22 AM   #4
KlaasJan
LQ Newbie
 
Registered: Aug 2006
Posts: 28

Original Poster
Rep: Reputation: 0
Tkinter menu: trying to use item label in callback

Here is the script again, now hopefully with the original indentation:

Code:
#!/usr/bin/env python3

from   tkinter     import *
from   tkinter.ttk import *

class UniMenu():
    def __init__(self,root):
        self.root = root
        geometrie = "800x50+600+200"
        self.root.geometry(geometrie)
        self.rubric = Label(self.root,text='Rubric:')
        self.rubric.pack(side=LEFT)

        # make a menu-bar for one item only:
        self.uMenu = Menu(self.root,type='menubar')

        # fill het hele menu:
        self.fillRubric()

        # put the newly created rubMenu below uMenu:
        self.uMenu.add_cascade(label='click',menu=self.rubMenu)

        # display the completed uMenu
        self.uMenu.pack(side=LEFT)

    def fillRubric(self):
        '''
        Main-rubrics and sub-rubrics come from a file called 'afdeling',
        which means rubric (!).
        A part of it looks like this, an indented line is a sub-rubric:

        Exact
            Wiskunde_statistiek
            Informatica
            Natuurkunde
            Astronomie
            Geologie
        Biologie
            Mens
        '''
        def show(a,b):
            print("Choice: %s: %s" % (a,b))

        # maak een vooralsnog onzichtbaar sub-menu rubMenu:
        rubricfile = "/kappa/data/afdeling"
        self.rubMenu = Menu(self.uMenu,tearoff=0)
        self.rubmap = {}
        rf = open(rubricfile,'r')
        mainRubCounter = 0
        subRubCounter = 0
        for fileLine in rf:
            # a sub-rubric starts in the import-file with at least one space:
            mainRubric = False if fileLine.startswith(" ") else True
            self.shortLine = fileLine.strip()

            if self.shortLine.startswith('#'): continue
            if len(self.shortLine) < 1: continue

            if mainRubric:

                if mainRubCounter > 0:
                    # A main-rubric can only be cascaded when allof its subs are read,
                    # at least that is what I think how it works,
                    # so I made it a one-fase-off procedure.
                    self.rubMenu.add_cascade(label=self.mainLabel,menu=self.rubmap[self.mainLabel])
                    print("Menu: rubMenu  Index: %s  Label: %s" % (self.rubMenu.index(self.mainLabel), self.mainLabel))
                self.mainLabel = self.shortLine
                mainRubCounter += 1
                self.rubmap[self.mainLabel] = Menu(self.rubMenu, tearoff=0)
            else:
                # command trial: lambda: show(self.mainLabel,self.shortLine))
                z = lambda: show(self.mainLabel,self.shortLine)
                self.rubmap[self.mainLabel].add_command(label=self.shortLine,command=z)
                print("Menu: rubmap[%s]  Index: %s  Label: %s" % (self.mainLabel,
                    self.rubmap[self.mainLabel].index(self.shortLine), self.shortLine))
        # De last mainRubric, because because mainRubric telkens een achterloopt:
        self.rubMenu.add_cascade(label=self.mainLabel,menu=self.rubmap[self.mainLabel])
        print("Menu: rubMenu  Index: %s  Label: %s" % (self.rubMenu.index(self.mainLabel), self.mainLabel))

    def doNothing(self):
        pass


root = Tk()
root.title('Experiment with a rubric tree')
um = UniMenu(root)
root.mainloop()
 
Old 08-13-2020, 08:51 AM   #5
smallpond
Senior Member
 
Registered: Feb 2011
Location: Massachusetts, USA
Distribution: Fedora
Posts: 4,147

Rep: Reputation: 1264Reputation: 1264Reputation: 1264Reputation: 1264Reputation: 1264Reputation: 1264Reputation: 1264Reputation: 1264Reputation: 1264
Thank you for the indented version. My example was too simple. You need to bind the value when the lambda is created so it is not evaluated later.

Code:
z = lambda a=self.shortLine: show(self.mainLabel,a)
 
Old 08-13-2020, 09:34 AM   #6
KlaasJan
LQ Newbie
 
Registered: Aug 2006
Posts: 28

Original Poster
Rep: Reputation: 0
smallpond, thank you for this eye-opener. I didn't know I could use the lambda arguments in this way.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Gnome 3.28.3 menu item dissapears from the system menu bodisha Linux - Newbie 0 10-06-2019 07:44 PM
x11vnc: clipboard and right click menu(context menu) "Paste" item not in sync Vilius Linux - Desktop 0 11-17-2017 11:46 PM
Why menu or item on right click can't configed by menu.xml? luofeiyu Debian 3 07-24-2017 12:45 PM
application menu disappeared and the main menu item has no response sunnior Ubuntu 12 11-03-2011 04:28 AM
mozilla xpm kmenu item desktop item cjae Linux - Newbie 3 04-06-2005 07:11 AM

LinuxQuestions.org > Forums > Linux Forums > Linux - Software

All times are GMT -5. The time now is 10:51 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration