Loop with after() in Tkinter
Question: I am a newbie with Tkinter and am still very unsure of the things I am trying
to do, hopefully it is not to stupid. Every help is welcome.

I want to use my Rasberry Pi to controll some motors. These motors put
ingredients together. It works fine in Python, but I want to have a GUI with a
few buttons. Each button should put a recipe in a function makerecipe. A
recipe consists of a list of times how long the different motors should be
activated. Makerecipe will activate the the GPIO pins.

Then a new function motor should start. Here it checks when the motors should
be deactivated. It is a simpel trick which works in Python, but I don't know
how to make it work in Tkinter. Every second a loop checks whether the time
passed is equal to what is in the recipe. If this is so, the motor is
deactivated.

    
    
    from Tkinter import *
    import ttk
    import time
    
    root = Tk()
    var = StringVar()
    uitput = StringVar() #I want to print what is happening to label L2
    uitput.set('Nothing')  #when program starts it says 
    conversie = [7, 11, 15] #I will use pins 7, 11 and 15 on the RPi, 
    moj = [0, 0, 2] #recipe 1, through Button 1, number of seconds the pins are True
    sob = [4, 0, 0] #recipe 2, through Button 2, number of seconds the pins are True
    
    #The following function activates the pins which are used in making the recipe
    #later this will just activate the pins, for now it shows it in a label on screen.
    #this seems to work
    
    def makerecipe(argu): 
        aa=[]
        for i in range(len(argu)):
            if argu[i]==0:
                a=('GPIO.output(', str(conversie[i]), 'False)')
                aa.append(a)
            else:
                b=('GPIO.output(', str(conversie[i]), 'True)')
                aa.append(b)
        uitput.set(aa)
        root.update_idletasks()
        root.motor(argu)
    
    #Next I want to have a function that looks at recipe and reads how long the
    #GPIO pins should be active. Then turns them off one at a time. I just don't
    #understand the after function. 
    #I think, but probably wrong, that my recipe was loaded in makerecipe and argu
    #has the value of the recipe because of the button, and I hoped I could pass argu
    #along to the function motor.
    
    
    def motor(motorinput):
        resultaat=('bla')
        uitput.set(resultaat)
    `enter code here`    cc=[]
        for MotorNum in range(max(motorinput)+1):
            if MotorNum in motorinput:
                if motorinput.index(MotorNum)==0:
                    c=("GPIO.output(",conversie[motorinput.index(MotorNum)],", False)")
                    cc.append(c)
                elif motorinput.index(MotorNum)==1:
                    d=("GPIO.output(",conversie[motorinput.index(MotorNum)],", False)")
                    cc.append(d)
                elif motorinput.index(MotorNum)==2:
                    e=("GPIO.output(",conversie[motorinput.index(MotorNum)],", False)")
                    cc.append(e)
            uitput.set(cc)
            root.update_idletasks()
            #root.after(1000, motor(alfa)) #This goes wrong. 
    
    B= Button(root, text="optie 1", command=lambda: makerecipe(moj))
    B.pack()
    L2=Label(root, textvariable=uitput, width=100)
    L2.pack()
    root.mainloop()
    

The reason I am printing my entire code here is that it might help to know
what the hell I am trying, it probably looks dreadful but I am trying to get
better at it.

First question is I apparently don't understand how to call the next function
motor inside my first function. It stops there and gives me: AttributeError:
motor

Second question is I know how to work with time.sleep, but I read everywhere
on this forum that you should not do this. So I am trying to use after, but
don't know how to use this properly.

I hope somebody can help this total novice. I understand the logic of Python
quite well, but Tkinter is a new way of thinking for me.


Answer: > First question is I apparently don't understand how to call the next
> function motor inside my first function. It stops there and gives me:
> AttributeError: motor

The problem is in last line of _makerecipe_ function:

    
    
    root.motor(argu)
    

The variable _root_ is a TK object which does not have a motor function.
That's the reason for AttributeError. Changing this line to:

    
    
    motor(argu)
    

Would remove this error.

> Second question is I know how to work with time.sleep, but I read everywhere
> on this forum that you should not do this. So I am trying to use after, but
> don't know how to use this properly.

You should use after because Tk has an eventloop running (the
_root.mainloop()_ call) to react based on events (like calling your functions
when a button is clicked, or a certain time has passed). But if you use
_time.sleep_ in your code, you might interfere with this eventloop.

The fix is that you should pass a function reference to _after_ , so Tk
eventloop would call that function when the right time comes. But here, you
are calling the function right away:

    
    
    root.after(1000, motor(alfa)) #This goes wrong.
    

This line is calling _motor_ (and passing _alfa_ as argument) and then passing
the return value of motor (which could be anything) to _root.after_.

This line should be like this:

    
    
    root.after(1000, motor, alfa)
    

Now we are telling _root_ to call _motor_ with the _alfa_ argument, after 1
second.

