mmkw43
Posts: 544
Joined: Tue Dec 24, 2013 6:18 pm

Tkinter root.after help

Fri Feb 26, 2016 3:53 pm

I have a lot of code that is working fine but I may have been under the wrong impression with using root.after for a delay.

Most of my code is setup in classes.

Code: Select all

root = Tk()

class Myclass:
        (initialize stuff):
        self.lbl1 = Label(root, etc)
        
        def blink(self):
             self.lbl1.place()
             root.after(500)
             self.lbl1.place_forget()

my = Myclass()

my()

root.mainloop()
I know this is a very basic question and as I say I have no problems doing the above but want to make sure it's alright to have root.after in a function that's in a class. (ok to use object oriented programming with tkinter?)I see so much that says it has to be "where" root.mainloop is but I'm guessing as long as I've specified "root" for the label in the class, it's perfectly fine?

Just want to be absolutely sure because I have a slight problem very rarely (sometimes I think it's because I'm really trying to get things to screw up to get any bugs out) and I have a feeling it's related to tkinter.

Let me ask --

If you can avoid using root.after, should you? As general practice?

I actually could set up a counting timer I think to give me the delays that I need. --thanks

scotty101
Posts: 3722
Joined: Fri Jun 08, 2012 6:03 pm

Re: Tkinter root.after help

Fri Feb 26, 2016 10:14 pm

You need to tell after which function to call after the delay period.

Code: Select all

root.after(500,self.blink)
Nothing wrong with using .after. It's better than using time.sleep.
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

mmkw43
Posts: 544
Joined: Tue Dec 24, 2013 6:18 pm

Re: Tkinter root.after help

Sat Feb 27, 2016 2:04 pm

I should have had that as

my.Myclass()

yes, I have been using it either as just a delay, which seemingly works fine -- root.after(500) -- or calling a function -- root.after(500,function).

so thanks for the reply. there is a very occasional problem in my code and I've determined it's one of the root.after delays I'm using. it may be something with a sloppy debounce problem at the GPIO input pin but sometimes a root.after pause will be completely ignored. Very simply,(there's a LOT more going on) and not written right --

root =Tk()

loop --
label on
root.after(1000)
label off
root.after(1000,loop)

root.mainloop()

once in a blue moon (and if I really try to get it to screw up), first root.after pause will just not be there -- so the label tries to blink but doesn't.

just using root.after like that, without calling a function, is ok right? it does work and have seen it like that in other code.

i'm also using time.sleep but in another thread.

scotty101
Posts: 3722
Joined: Fri Jun 08, 2012 6:03 pm

Re: Tkinter root.after help

Sat Feb 27, 2016 5:14 pm

I've used Tkinter for a while now and have never used .after like that.

I'll check the documentation.

Edit: I can't find any examples of using .after without specifying a callback function.
This link below seems to clarify that too
http://stackoverflow.com/questions/2575 ... ter-method
Last edited by scotty101 on Sat Feb 27, 2016 11:54 pm, edited 1 time in total.
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

mmkw43
Posts: 544
Joined: Tue Dec 24, 2013 6:18 pm

Re: Tkinter root.after help

Sat Feb 27, 2016 7:54 pm

Scotty -- thanks. One of those things that I misread and because it "does" work just kept it in there. Anyway -- simple enough, I'll just do a function for ON and one for OFF. This is a good thing because after months of work, the only flaw I had. Thanks so much. !

mmkw43
Posts: 544
Joined: Tue Dec 24, 2013 6:18 pm

Re: Tkinter root.after help

Sun Feb 28, 2016 2:27 pm

I can tell getting rid of that root.after was the problem in how it's acting so far.

Scotty -- would like to ask you something. I just started learning python and tkinter about a year ago, I'm a hobbyist and there is another minor issue I need to clear up.

Code: Select all

root = Tk()

class Myclass:
     def__init__(self):
             self.variables

     def myfunction(self):
              do something

m = Myclass()

root.mainloop()
All of my classes are written like this. If there is a tkinter widget in a class I refer to it as you should --
lb = Label(root, etc)

But one thing I notice in other code (but wasn't talked about in the tutorials I followed, is using root in the argument area. ?

Code: Select all

root = Tk()

class Myclass:
        def__init__(self,root):
                 self.variables
      
        def myfunction(self,root):
                  do something

m = Myclass(root)
                 
root.mainloop()

Based on the first example (that I use) isn't adding root redundant? not? why?

My code works fine without it -- when you leave it out, isn't it all automatically at "root level" ? --thanks

User avatar
RogerW
Posts: 285
Joined: Sat Dec 20, 2014 12:15 pm
Location: London UK

Re: Tkinter root.after help

Sun Feb 28, 2016 4:10 pm

To me your use of a class object does not make sense. Also root is not a keyword - just the name of a variable. A lot of sample code uses root as the name of a Tk object which "owns" the main window.

This code does what I think you are trying to do. If you are using python 2 change tkinter to Tkinter.

Code: Select all

import tkinter as tk

class Myclass(tk.Tk):
    # Myclass inherits Tk. That is it is a modified Tk
    def __init__(self):
        # initialise the base class
        tk.Tk.__init__(self)
            
        # create a label
        self.lbl1 = tk.Label(self, text = 'Label text')
        self.lbl1.pack()
        self.lbl1.visible = True
        
        # after 500 msec call blink
        self.after(500,self.blink)
        
    def blink(self):
        # flip label visibility
        if self.lbl1.visible:
            self.lbl1.pack_forget()
            self.lbl1.visible = False
        else:
            self.lbl1.pack()
            self.lbl1.visible = True
            
        # call this function again after 500 msec
        self.after(1000,self.blink)

# create a Myclass object called root
root = Myclass()
# call mainloop to make it run
root.mainloop()
I have used the name root but any other name would do. I hope this helps - come back if it does not make sense.

mmkw43
Posts: 544
Joined: Tue Dec 24, 2013 6:18 pm

Re: Tkinter root.after help

Sun Feb 28, 2016 4:23 pm

which doesn't make sense, the first example (which I use) or the second ?

the tutorials I studies were like that -- typically root or app = Tk()


from tkinter import *
root = Tk()

# it's the use of root in the argument space that I don't get -- I've seen it like that in some code (bad code maybe?)

root.mainloop()

maybe I'm not making sense with my question.

everything works fine the way I have it (never an error) -- just want to clarify some things.

User avatar
RogerW
Posts: 285
Joined: Sat Dec 20, 2014 12:15 pm
Location: London UK

Re: Tkinter root.after help

Sun Feb 28, 2016 4:56 pm

which doesn't make sense, the first example (which I use) or the second ?
I think both of them. I am not clear what Myclass represents. Usually (but not always) a class object represents something concret, for instance a window.
the tutorials I studies were like that -- typically root or app = Tk()
I agree that many sample codes use this sort of structure. It is a style that I personally dislike but does work and many people use it. For instance this very simple program does work.

Code: Select all

import tkinter as tk

root = tk.Tk()
tk.Label(root,text = 'Hello world').pack()
root.mainloop()
from tkinter import *
root = Tk()
The import statement has a number of forms. This one imports all the definitions in tkinter even iff you only use a few. In more complicated programs there is a danger that tkinter will use a name that you also use. This can lead to errors.

Code: Select all

import tkinter as tk
imports tkinter but when you use an identifier from tkinter you must qualify it with tk. (e.g.tk.Tk()). This avoids the name clash problem. Again it is a matter of personal style.

In one of your codes you set

Code: Select all

x = Myclass()
and in another

Code: Select all

x = Myclass(root)
In the second you are passing root to the constructor(__init__) as a parameter. It is not clear to me what you do with that parameter. In any case root is a global variable so you can use it anyway.
everything works fine the way I have it (never an error) -- just want to clarify some things.
Good - in my view it is good for a program to work but even better if you understand why it works.

mmkw43
Posts: 544
Joined: Tue Dec 24, 2013 6:18 pm

Re: Tkinter root.after help

Mon Feb 29, 2016 1:04 am

What my question boils down to is this -- very simply.

Code: Select all

from tkinter import *

root = Tk()

class Myclass:
        def __init__(self,master):      #can leave out "master" and it works fine -- master means root right?
                 self.variable
                 self.lbl = Label(root,etc)
        
        def function():
                 self.dostuff

m = Myclass(root)                   #can leave out "root" here also and it works fine

this is the guy whos tutorials I watched a lot and this shows what I mean.
https://www.youtube.com/watch?v=IYHJRnVOFlw

very simply, I just want to know why I can leave out root in those 2 places without any effect on the program? I can do that with all my classes. Just want to learn what the "importance" of root is.I do include root whenever I have a widget in a class, like the label above.

Is including it redundant? (not needed?) because everything is at root level anyway?

mmkw43
Posts: 544
Joined: Tue Dec 24, 2013 6:18 pm

Re: Tkinter root.after help

Mon Feb 29, 2016 1:27 am

holy crap ! I didn't realize I had 266 posts ! lol

mmkw43
Posts: 544
Joined: Tue Dec 24, 2013 6:18 pm

Re: Tkinter root.after help

Mon Feb 29, 2016 1:35 am

I think I have this all screwed up because of that youtube code example I saw.

Master is only used when you use a frame?

and using root when creating the object plays into that? and necessary?

User avatar
RogerW
Posts: 285
Joined: Sat Dec 20, 2014 12:15 pm
Location: London UK

Re: Tkinter root.after help

Mon Feb 29, 2016 9:35 am

Master is only used when you use a frame?
Esentially yes. Remember root and master are only names that you write. They are not keywords.
All window objects except the root window (owned by the Tk object) need to know their parent. That is why when you create a frame or indeed any other widget the first parameter to the constructor is the object that represents the parent window. Some sample codes use the name parent, others master - this is only convention.
Master is only used when you use a frame?
I think I have covered this above.

Code: Select all

import tkinter as tk

root = tk.Tk()
frame = tk.Frame(root)
frame.pack()
lbl = tk.Label(frame,text = 'Hello world')
lbl.pack()
root.mainloop()
In this simple program root is the parent of frame and frame is the parent of lbl.

I would not write the code like this in a real program but it explains the way widgets are linked together.

scotty101
Posts: 3722
Joined: Fri Jun 08, 2012 6:03 pm

Re: Tkinter root.after help

Mon Feb 29, 2016 11:48 am

RogerW wrote: Esentially yes. Remember root and master are only names that you write. They are not keywords.
Not strictly true!
master is an attribute held by each Tkinter object from the base Tk() through to Label() and all between

Consider this example for python3

Code: Select all

from tkinter import *

top = Tk()
top.title("Application Name")

msg = Message(top)
msg['text'] = msg.master.title() + "Hello"
msg.pack()

top.mainloop()
We can access the parent of msg by accessing it's 'master'
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

User avatar
RogerW
Posts: 285
Joined: Sat Dec 20, 2014 12:15 pm
Location: London UK

Re: Tkinter root.after help

Mon Feb 29, 2016 12:00 pm

Not strictly true!
I disagree - root and master are not keywords. It is true that master is an attribute of the widget classes used to store the parent parameter passed to the constructor but that does not make it a keyword.

I was trying to keep things simple for the OP and explain the ownership hierarchy.

scotty101
Posts: 3722
Joined: Fri Jun 08, 2012 6:03 pm

Re: Tkinter root.after help

Mon Feb 29, 2016 12:03 pm

Agreed but master is a special term defined in the Tkinter objects where as root isn't.
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

Return to “Graphics programming”