LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (http://www.linuxquestions.org/questions/programming-9/)
-   -   How to: tkinter-python to monitor a file, add buttons automatically, and exit cleanly (http://www.linuxquestions.org/questions/programming-9/how-to-tkinter-python-to-monitor-a-file-add-buttons-automatically-and-exit-cleanly-4175432051/)

donnied 10-13-2012 01:37 PM

How to: tkinter-python to monitor a file, add buttons automatically, and exit cleanly
 
I had difficulties creating a program that used tkinter and python that allowed a file to be monitored, buttons to be added, and the program to be exited cleanly.

This arose in part from an awkward series of root.mainloop() and Tkinter.Tk() instances that were being generated and could not be exited cleanly even with the following code that should have ended it (this code is overkill – sys.exit alone should kill the program) –if you’re looking to kill Tkinter much of this will do it:
Code:

    def stop():
            global win
            win.quit()
            try:
                    del(win)
            except:
                    pass
            raise SystemExit
            sys.exit()
            return False

See posts such as this:
http://stackoverflow.com/questions/5...-quit-properly

If you’re trying to run processes concurrently with tkinter and it won’t close – the structure is most likely wrong. GTK had tolerated an abuse of the structure – allowing multiple main windows to be generated – tkinter won’t. Though I had originally used threading, most likely improperly as well, this comes with several dangers and wasn’t working and wasn’t necessary for what I was trying to do. The after method allowed the tkinter window and file checking to run seemingly simultaneously.

This post is very helpful in understanding / using `after`:
http://stackoverflow.com/questions/4...ers-event-loop

Basically, for a program to keep checking a file for changes and to reflect those changes in a list of buttons – the normal root = Tkinter.Tk() and root.main() format must be followed within the body. The looping and while statements are accomplished using “after”.

Basically, I used one function that completed once to construct the initial buttons (and they’re placed at the top as new buttons are added below) – makethelistofbuttons(), then each cycle runs refresh() which only adds new buttons.

[In gtk, I had originally attempted (with semi-success) to generate and destroy the list of buttons with each iteration of refresh(). That did not work here.]

The code necessary to create the file checking (seemingly concurrent) to running the tkinter window:
Code:

    bobsyouruncle = False
   
    def dothis():
            global bobsyouruncle
            try:
                    if bobsyouruncle == False:
                            bobsyouruncle = True
                            makethelistofbuttons()
                    else:
                            refresh()
            except:
                    pass
            win.after(2000,dothis)
   
    win.after(2000, dothis)
    win.mainloop()

Note – win.after is included in dothis() and within the main program.

To show how the buttons are read in and generated the complete code is provided below. It may also be worth mentioning that some people have warned against `win.update()` – but it seemed to be integral to getting the program to work.

Code:

    import Tkinter
    from Tkinter import *
    import sys
    import time
   
   
    win = Tkinter.Tk()
   
    somefilefile = open("users.txt", 'r')
  listofusers = []
   
   
    def findadditions(line):
            line = line.replace('"', '').strip()
            linelist = line.split()
            username = linelist[1]
            userstatus = checkforuser(username)
            if not userstatus:
                    global listofusers
                    global win
                    listofusers.append(username)
                    newbuttonname = username
                    newbuttonname = Tkinter.Button(win, text = username, command = lambda name=username:click_one(name))
                    newbuttonname.pack()
                    win.update()
   
    def checkforuser(username):
            return username in listofusers
   
    def click_one(newbuttonname):
        print newbuttonname, “was clicked”
   
   
    def refresh():
            global win
            somefilefile = open("users.txt", 'r')
            for line in somefilefile:
                    findadditions(line)
            somefilefile.close()
            win.update()
   
    def stop():
            global win
            win.quit()
            try:
                    del(win)
            except:
                    pass
            raise SystemExit
            sys.exit()
            return False
   
    def makethelistofbuttons():
            global win
            global listofusers
            try:
                    somefilefile.close()
            except:
                    pass
            stopbutton = Tkinter.Button(win, text="Quit", command=lambda win=win:stop()).pack()
            refreshbutton = Tkinter.Button(win, text = "refresh", command = refresh).pack()
            somefilefile = open("somefile.nlist", 'r')
            for line in somefilefile:
                    findadditions(line)
            somefilefile.close()
            win.update()
   
   
   
    bobsyouruncle = False
   
    def dothis():
            global bobsyouruncle
            try:           
                    if bobsyouruncle == False:
                            bobsyouruncle = True
                            makethelistofbuttons()
                    else:
                            refresh()
            except:
                    pass
            win.after(2000,dothis)
   
    win.after(2000, dothis)
    win.mainloop()
   
    try:
            writethisdown.close()
    except:
            pass
   
    raise SystemExit
    sys.exit()



All times are GMT -5. The time now is 01:00 AM.