user5473311
user5473311

Reputation:

tkinter timer use with entry widgets

from  tkinter import * 
from  threading import Timer 
.......

def getdata(dval):
    global log,entryWidget,txtf,infile,lout
    ff="c:\\downloads\test\logs\\log1.log"
    flog=open(ff,encoding="utf-8")
    infile= flog.read()
    flog.close()  

def getlog(sval):
    global log,entryWidget,txtf,infile,lout
    txtf.delete ('1.0','end')
    inf =entryWidget.get().strip()
    if  inf == "scan":
      gdata = getdata("")
      txtf.insert (END,gdata)
   else:
     gdata=str(datetime.now( ))+"\n"
     txtf.insert (END,gdata)
   gdata=""

   ev=Timer(60,getlog,[lout])
   ev.start()

def runscan():
    global log,entryWidget,txtf,infile,lout
    root =Tk()
    root.title("Scan  log")t
    textFrame = Frame(root)
    txtf= Text(textFrame,width=60,height=18,font=("MS Sans Serif bold",8))
    entryWidget = Entry(textFrame)

    textFrame.grid(row=200,column=200)
    textFrame.bind("<Button-1>", getlog(lout)

    txtf.grid(row=0,column=1)

    entryWidget["width"] = 30
    entryWidget.bind('<Return>',getlog(10))
    entryWidget.grid(row=25,column=1)

    ev=Timer(60,getlog,[10])
    ev.start()

    root.mainloop()

if __name__ == "__main__":
    runscan()

The timer works fine every 60 secs but the Entrywidget does not.
If i take out the timer the Entrywidget works ok.
So somewhere the timer thread locks up the widget input.
It would seem that the timer in the main loop
needs a reset function and not in the getlog function.

Upvotes: 0

Views: 416

Answers (2)

user5473311
user5473311

Reputation:

def runscan():
    global log,entryWidget,txtf,infile,lout
    lout=10
    root =Tk()
    root.title("Scan Mirc log")
    root["padx"] = 2
    root["pady"] = 2
    root.configure(background='grey')
    w = 400 # width for the Tk root
    h = 360 # height for the Tk root
    ws = root.winfo_screenwidth() # width of the screen
    hs = root.winfo_screenheight() # height of the screen
    x = ws - w-20
    y = hs - h -60
    root.geometry('%dx%d+%d+%d' % (w, h, x, y))
    textFrame   = Frame(root)
    entryWidget = Entry(root)
    entryWidget["width"] = 30

    txtf= Text(textFrame,width=65,height=23,font=("MS Sans Serif bold",8))

    textFrame.bind("<Button-1>",getlog,[lout])
    entryWidget.bind('<Return>',getlog,[lout])

    txtf.grid(row=0,column=1)
    textFrame.grid(row=20,column=1)
    entryWidget.grid(row=30,column=1)

    txtf.after (60000,getlog,[lout])

    root.mainloop()

if __name__ == "__main__":
    runscan()  

cleaned it up and corrected some errors
and it works fine now

Upvotes: 0

Bryan Oakley
Bryan Oakley

Reputation: 386342

You don't need to use the Timer class. Tkinter has a way to run code in the future. The problem with the Timer class is that it uses threads, and tkinter is not thread-safe.

Here's an example of how to run getlog every 60 seconds. Call it once, and it will run every minute until the program exits.

def getlog():
    txtf.delete ('1.0','end')
    inf =entryWidget.get().strip()
    if  inf == "scan":
        gdata = getdata("")
        txtf.insert (END,gdata)
    else:
        gdata=str(datetime.now( ))+"\n"
        txtf.insert (END,gdata)
    gdata=""

    txtf.after(60000, getlog)

Note that if getdata("") can block, this will still cause your program to hang. If that's the case you'll have to continue to use threads, but you'll have to have your thread get the data and post it to a thread-safe queue, and have your GUI thread poll that queue. Without knowing what getdata does, I can't be more specific.

Upvotes: 1

Related Questions