Tkinter event handlers and command callbacks

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • luofeiyu
    New Member
    • Jul 2011
    • 18

    Tkinter event handlers and command callbacks

    Code:
    from Tkinter import *
    fields = 'Name', 'Job', 'Pay'
    
    def fetch(event,entries):
       for entry in entries:
           print 'Input => "%s"' % entry.get()       # get text
           print  event.widget 
          
          
    def makeform(root, fields):
       entries = []
       for field in fields:
           row = Frame(root)                           # make a new row
           lab = Label(row, width=5, text=field)       # add label, entry
           ent = Entry(row)
           row.pack(side=TOP, fill=X)                  # pack row on top
           lab.pack(side=LEFT)
           ent.pack(side=RIGHT, expand=YES, fill=X)    # grow horizontal
           entries.append(ent)
       return entries
    
    if __name__ == '__main__':
       root = Tk()
       ents = makeform(root, fields)
       root.bind('<Return>', lambda event,entries=ents: fetch(event,entries))       
       Button(root, text='Fetch', command= lambda event:fetch(event,entries)).pack(side=LEFT)  # #how to revise it?
       root.mainloop()
    in the code ,the bind method is ok, how to revise "command=la mbda event:fetch(eve nt,entries)",to make it work too??
    Last edited by bvdet; Aug 24 '11, 01:02 PM. Reason: Assign a more descriptive title
  • bvdet
    Recognized Expert Specialist
    • Oct 2006
    • 2851

    #2
    The button command callback does not receive an argument. If you want the button to respond to an event and the callback receive the event as an argument, bind an event to it, possibly "<ButtonRel ease-1>".
    Code:
    from Tkinter import *
    fields = 'Name', 'Job', 'Pay'
    
    def fetch(entries, event=None):
       for entry in entries:
           print 'Input => "%s"' % entry.get()       # get text
           if event:
               print  event.widget 
          
          
    def makeform(root, fields):
       entries = []
       for field in fields:
           row = Frame(root)                           # make a new row
           lab = Label(row, width=5, text=field)       # add label, entry
           ent = Entry(row)
           row.pack(side=TOP, fill=X)                  # pack row on top
           lab.pack(side=LEFT)
           ent.pack(side=RIGHT, expand=YES, fill=X)    # grow horizontal
           entries.append(ent)
       return entries
    
    if __name__ == '__main__':
       root = Tk()
       ents = makeform(root, fields)
       root.bind('<Return>', lambda event, entries=ents: fetch(entries, event))
       Button(root, text='Fetch', command=lambda:fetch(ents)).pack(side=LEFT)  # #how to revise it?
       root.mainloop()

    Comment

    • dwblas
      Recognized Expert Contributor
      • May 2008
      • 626

      #3
      First, your title makes this thread appear to be a "HowTo", i.e. code that explains how to do something, so you may get fewer readers/respondents as a result.
      how to revise "command=la mbda event:fetch(eve nt,entries)",to make it work too??
      What does this mean? If you mean that your want to pass something to a function when a button is pressed, Python provides "partial". Note that Guido does not like lambda, and planned to remove it in Python 3 as there are better ways to do things. Also, in the fetch() function, you print the same event for each entry in entries. It should be indented at the same level as the for() statement so it only prints once.
      Code:
      from Tkinter import *
      from functools import partial
        
      def fetch(event, entries):
             for entry in entries:
                 print 'Input => "%s"' % entry.get()       # get text
                 if event:
                     print  event.widget 
           
           
      def makeform(root, fields):
             entries = []
             for field in fields:
                 row = Frame(root)                           # make a new row
                 lab = Label(row, width=5, text=field)       # add label, entry
                 ent = Entry(row)
                 row.pack(side=TOP, fill=X)                  # pack row on top
                 lab.pack(side=LEFT)
                 ent.pack(side=RIGHT, expand=YES, fill=X)    # grow horizontal
                 entries.append(ent)
             return entries
           
      if __name__ == '__main__':
             fields = 'Name', 'Job', 'Pay'
             root = Tk()
             ents = makeform(root, fields)
      
             ## this can be converted to "partial" as well if you want
             root.bind('<Return>', lambda event, entries=ents: fetch(entries, event))
      
             xb =Button(root, text='Fetch')
             xb.pack(side=LEFT)
      
             ## note that both 'root' & 'xb' bind an object to an event
             ## that is sent to the function
             xb.bind("<Button-1>", partial(fetch, entries=ents))
             root.mainloop()

      Comment

      • luofeiyu
        New Member
        • Jul 2011
        • 18

        #4
        get event attribution

        Code:
        from Tkinter import *
        
        def fetch(x):
               print  x.type,x
             
             
        if __name__ == '__main__':
               root = Tk()
               root.bind('<Return>', fetch)
               root.mainloop()
        i can get output :
        2 <Tkinter.Even t instance at 0xb742986c>

        Code:
        from Tkinter import *
        
        def fetch(x):
               print  x.type,x
             
             
        if __name__ == '__main__':
               root = Tk()
               button=Button(root,text='Fetch')
               button.pack()
               button.bind('<Return>',fetch)       
               root.mainloop()
        why i can get nothing when i click enter??

        Comment

        • dwblas
          Recognized Expert Contributor
          • May 2008
          • 626

          #5
          To capture a "Return", you have to set the focus. Otherwise, the focus is not set on the widget so the Return goes to the root window or whatever has focus, and you don't have any bindings for it.
          Code:
          rom Tkinter import *
           
          def fetch(x):
                 print x, type(x)
           
          if __name__ == '__main__':
                 root = Tk()
                 button=Button(root,text='Fetch')
                 button.pack()
                 button.focus_set()
                 button.bind('<Return>',fetch)       
                 root.mainloop()

          Comment

          • luofeiyu
            New Member
            • Jul 2011
            • 18

            #6
            you lose f in rom (it is from),i made a try,it'ok,but there is still a problem,
            when i finish my first enter,it's ok,there is output ,
            when i have a try for the second time ,there is no output??

            Comment

            • bvdet
              Recognized Expert Specialist
              • Oct 2006
              • 2851

              #7
              Are you losing focus after the first event? You can reset the focus in the callback with x.widget.focus_ set()

              Comment

              • luofeiyu
                New Member
                • Jul 2011
                • 18

                #8
                Code:
                from Tkinter import *
                     
                def fetch(x):
                           print x, type(x)
                     
                if __name__ == '__main__':
                           root = Tk()
                           button=Button(root,text='Fetch')
                           button.pack()
                           button.focus_set()
                           button.grab_set()
                           button.bind('<Return>',fetch)       
                           root.mainloop()
                add button.grab_set (),it's ok now
                Last edited by bvdet; Aug 25 '11, 03:14 AM. Reason: Add code tags

                Comment

                Working...