954,549 Members — Technology Publication meets Social Media
Username:
Password:
Lost login information?
Have something to say? Contribute New Article Reply to this Article

Tkinter user-input

I am writing a small tkinter-app involving user keyboard-input, and want to control the range of acceptable input-characters. I'm currently using an Entry-widget, but haven't been able to access the individual characters AS THEY ARE ENTERED. What I (think I:confused:) need is somthing like the 'command=' option (as in the Button-widget), which would call a function at each keyboard-entry. Can anyone point me in the right direction? Thanks.

shr2408
Newbie Poster
10 posts since Nov 2006
Reputation Points: 10
Solved Threads: 0
 

This should help you ...

# bind and show a key event with Tkinter

from Tkinter import *

root = Tk()
prompt = '      Press any key      '
label1 = Label(root, text=prompt, width=len(prompt))
label1.pack()

def key(event):
    if event.char == event.keysym:
        msg = 'Normal Key %r' % event.char
    elif len(event.char) == 1:
        msg = 'Punctuation Key %r (%r)' % (event.keysym, event.char)
    else:
        msg = 'Special Key %r' % event.keysym
    label1.config(text=msg)

root.bind_all('<Key>', key)

root.mainloop()
vegaseat
DaniWeb's Hypocrite
Moderator
5,989 posts since Oct 2004
Reputation Points: 1,345
Solved Threads: 1,417
 

vegaseat, many, MANY thanks; from the look of your snippet it seems to be exactly what I need. Cheers.

shr2408
Newbie Poster
10 posts since Nov 2006
Reputation Points: 10
Solved Threads: 0
 

I imbedded vegaseat's code into my app - see below - and it works (of course), except for the final line:

def key(self, event):
        if event.char == event.keysym:
          msg = 'Normal Key %r' % event.char
        elif len(event.char) == 1:
          msg = 'Punctuation Key %r (%r)' % (event.keysym, event.char)
        else:
          msg = 'Special Key %r' % event.keysym
        self.l00.config(text=msg)


When I enter something, I get the message:

AttributeError: Application instance has no attribute 'l00'

With "self." removed, the message is:

NameError: global name 'l00' is not defined

I imagine that I must have a scope problem, which I have spent two days trying to solve, but to no avail. l00, BTW, is a label-widget, which was instantiated using the same class:

self.l00 = Label(self, borderwidth=1, relief=RIDGE, anchor=W)
self.l00.grid(row=0, column=0, columnspan=3)


It may be a simple solution, but I can't see it; can someone help me out again?

And another quick point; is it possible to give widgets a sort of GLOBAL attribute, to make them generally accessable within an app.?

Thanks.

shr2408
Newbie Poster
10 posts since Nov 2006
Reputation Points: 10
Solved Threads: 0
 

Can you give us the whole class?

Just a note, 'l00' is a heck of a variable name, looks a lot like the number '100', I would avoid it!

vegaseat
DaniWeb's Hypocrite
Moderator
5,989 posts since Oct 2004
Reputation Points: 1,345
Solved Threads: 1,417
 

Can you give us the whole class?

Just a note, 'l00' is a heck of a variable name, looks a lot like the number '100', I would avoid it!

Thanks; here it is, hope you can figure out my beginner's scribblings;)

class Application(LabelFrame):              # 3
    def __init__(self, rowpos, colpos, framenr, crWidg, master=None):
        LabelFrame.__init__(self, master)#, name='lf'+chr(framenr+ord('0')))  # 4
    if crWidg == 1: 
          self.grid(row=rowpos, column=colpos)                    # 5
      self.createWidgets(framenr, rowpos, colpos)
    elif crWidg == 0:
          self.grid(row=rowpos, column=colpos, columnspan=3, sticky=W)                    # 5
      lident = 'l'+chr(rowpos+ord('0'))+chr(colpos+ord('0'))
          self.l00 = Label(self, borderwidth=1, relief=RIDGE, anchor=W,        \
                           name=lident, text="                 "+lident+"             ")
          self.l00.grid(row=0, column=0, columnspan=3)
    else:
          self.grid(row=rowpos, column=0, columnspan=3, sticky=E)                    # 5
          self.e01 = Entry(self, borderwidth=0, relief=RIDGE, width=colpos)
          self.e01.grid(row=rowpos, sticky=E)
      self.e01.bind_all('<Key>', self.key)
      self.e01.focus_set()

#
# this function generates a widget (cell) name relating to its position within the LabelFrame
#    
    def get_cell_ident(self, framenr, cells_per_frame_inX, cells_per_frame_inY, rownum, colnum):
      rowst, colst = divmod(framenr,cells_per_frame_inX)            # get result and remainder
      rowst = rowst*cells_per_frame_inY                             # start-nr of the row-cell
      colst = colst*cells_per_frame_inX                             # start-nr of the column-cell
      text = chr(rowst+rownum+ord('0'))+ \
             chr(colst+colnum+ord('0'))                             # this is the ident described in the top table       
      return text

#
# this function instantiates m * n Label-widgets and 'grid's them into the previously instantiated LabelFrame
#      
    def createWidgets(self, framenum, rowposn, colposn):
        for rownr in range(0,cellsperframeinY):                       # WITHIN each frame, process .....
          for colnr in range(0,cellsperframeinX):                     #  .... each cell.
            ident = self.get_cell_ident(framenum, cellsperframeinX, \
                                   cellsperframeinY, rownr, colnr)
            self.wlab = Label(self, borderwidth=2, relief=RIDGE, \
                              text=ident, name='w'+ident)
            self.wlab.grid(row=rownr, column=colnr, ipadx=5, ipady=5)
#
# this is the function which has been bound to the Entry-box 'e01' (instantiated above in Application)
#
    def key(self, event):
        if event.char == event.keysym:
          msg = 'Normal Key %r' % event.char
        elif len(event.char) == 1:
          msg = 'Punctuation Key %r (%r)' % (event.keysym, event.char)
        else:
          msg = 'Special Key %r' % event.keysym
        l00.config(text=msg)
shr2408
Newbie Poster
10 posts since Nov 2006
Reputation Points: 10
Solved Threads: 0
 

If crWidg is not 0, then your self.l00 label is never created. Hence your AttributeError. The instance prefix self. makes that variable global to the class methods.

vegaseat
DaniWeb's Hypocrite
Moderator
5,989 posts since Oct 2004
Reputation Points: 1,345
Solved Threads: 1,417
 
If crWidg is not 0, then your self.l00 label is never created. Hence your AttributeError. The instance prefix self. makes that variable global to the class methods.

Thanks, but I'm pretty sure that the label (now lab00, BTW) *is* correctly being created, at least it appears in the window. Possibly the problem lies in the fact that the app calls Application three times (with crWidg == 0), thereby generating 3 labels, ALL called lab00. I know that it's possible to assign a name to each instance (using the 'name=' option, e.g. lab00, lab01, lab02), but I haven't yet been able to subsequently address the individual instances using these assigned names. Is this not possible in tkinter (or python?)?

shr2408
Newbie Poster
10 posts since Nov 2006
Reputation Points: 10
Solved Threads: 0
 

You can use eval() to turn a string into an object.

Ene Uran
Posting Virtuoso
1,723 posts since Aug 2005
Reputation Points: 625
Solved Threads: 213
 
You can use eval() to turn a string into an object.

Sorry, have tried a couple of examples of eval() but with only syntax-error results:-| . Is eval() a method, a function, an option, or what? Also, what content does the string have to have? Could you give me an example of its use? Thanks.

shr2408
Newbie Poster
10 posts since Nov 2006
Reputation Points: 10
Solved Threads: 0
 

It's not the eval() function, but the exec() function. Here is a Tkinter example ...

# creating multilabels in Tkinter

from Tkinter import *

root = Tk()

# create a list of labels
labels = []
for k in range(4):
    labels.append(Label(root, text='Label in grid row %d' % k))

# now assign a grid position to each label
for  ix, label in enumerate(labels):
    label.grid(row=ix, column=0, pady=5)

# change a label using labels list index
labels[0].config(fg='blue')
labels[1].config(fg='red')

# give each label in labels list a nice name
exec("lab00 = labels[0]")
exec("lab01 = labels[1]")
exec("lab02 = labels[2]")
exec("lab03 = labels[3]")

# test the nice name
lab02.config(bg='green')
lab03.config(bg='yellow')

root.mainloop()
vegaseat
DaniWeb's Hypocrite
Moderator
5,989 posts since Oct 2004
Reputation Points: 1,345
Solved Threads: 1,417
 

It's not the eval() function, but the exec() function. Here is a Tkinter example ...

# creating multilabels in Tkinter

from Tkinter import *

root = Tk()

# create a list of labels
labels = []
for k in range(4):
    labels.append(Label(root, text='Label in grid row %d' % k))

# now assign a grid position to each label
for  ix, label in enumerate(labels):
    label.grid(row=ix, column=0, pady=5)

# change a label using labels list index
labels[0].config(fg='blue')
labels[1].config(fg='red')

# give each label in labels list a nice name
exec("lab00 = labels[0]")
exec("lab01 = labels[1]")
exec("lab02 = labels[2]")
exec("lab03 = labels[3]")

# test the nice name
lab02.config(bg='green')
lab03.config(bg='yellow')

root.mainloop()

**Great**, just what I needed. On further investigation, didn't need the 'exec' function (at least, not at the moment, but I'm sure that its time WILL come), but your tip on filling the array with labels and then gridding them was just the ticket. Now my app works just as I wanted. Many, many thanks:p.

PS Just one extra thought; is it possible in tkinter to *simulate* a keypress? Clever as tkinter is, just thought that it might be. Thanks again

shr2408
Newbie Poster
10 posts since Nov 2006
Reputation Points: 10
Solved Threads: 0
 

This question has already been solved

Post: Markdown Syntax: Formatting Help
You