RDS
Posts: 636
Joined: Tue Oct 06, 2015 8:17 am
Location: Lancashire, UK

Running a Procedure from a tkinter button or an event

Wed Feb 14, 2018 11:06 pm

I have a program that monitors the output of my Solar Panels.

It uses tkinter to provide a graphical interface and this works well. The program calls a procedure whenever a GPIO goes from High to Low. I have a test button on the tkinter window that I can use for testing purposes. The action initiated by the test button is just to call exactly the same procedure that is called by the interrupt.

However, when the procedure is called by the interrupt, I have to include (self) at the end of the Procedure name. When I run the procedure from my test button, I have to remove the word 'self' and just leave the brackets (). Failure to do this results in errors.

Is there any way around this because it defeats the object of my test button, if I have to alter my program whenever I want to use it.

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

Re: Running a Procedure from a tkinter button or an event

Thu Feb 15, 2018 11:53 am

Share your code or a small working example of it that demonstrates your problem.
I'll then be able to help.
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

RDS
Posts: 636
Joined: Tue Oct 06, 2015 8:17 am
Location: Lancashire, UK

Re: Running a Procedure from a tkinter button or an event

Thu Feb 15, 2018 5:33 pm

Thank you.
I should point out scotty, that I wrote this program with the tkinter interface following the fantastic help you gave my in early January on another thread, to use tkinter but I just could not get to grips with 'Classes' in your program, so I wrote this one without them but you certainly helped me along the way. I realise that the program lacks programming efficiency in a lot of areas but it was more important for me to start with to get it working. I hope to tidy it up later.

I have attached the full code below.
My GPIO pin is held high until the light sensor detects that an LED flashes and I have used an event to detect a falling pulse.
(This works reasonably well but is not as accurate as a program I wrote before that just detects when the pulse is low)

If I run the program without the word 'self' within the brackets in the procedure flashLED, it returns the following error when a pulse is detected and the procedure flashLED is executed

Code: Select all

TypeError: flashLED() takes no positional arguments but one was given
If I add 'self' within the brackets of the procedue flashLED and then press the TEST button it returns the following error when a pulse is detected and the procedure flashLED is executed
TypeError: flashLED() missing one required positional argument: 'self'

I would like to be able to use the TEST button or operate normally from the light sensor, without having to change the program.

Code: Select all

# Program started on 21st January 2018

from tkinter import *
import RPi.GPIO as GPIO
from datetime import  *
from time import *
from math import *

import os
os.system("xdotool getactivewindow windowmove 515 175 windowsize 600 545")

GPIO.setmode(GPIO.BCM)
GPIO.setup(10, GPIO.IN)

file = open('Last_Detect.csv', 'r')
lastreading = int(file.read ())
file.close()

breakeven = 1000
fullscale = 314
detected = 0
lpulse = ""
kwhr = 0
kwhrhigh = 0
kwhrlast = 0
displaytext = ""
timenow = time()
xneedle = 0
yneedle = 0
needlelength = 70
plotkwhr = 0
colourr = ""

root = Tk() #Draws the window

detect = lastreading #Set starting point in case program is re-run during the day

def redCircle():
    global detect
    MeterCanvas.create_oval(20, 20, 60, 60, width=0, fill='red')
    
    
def flashLED(self): # put self within brackets when operating from light sensor
    global detect
    global detected
    global timenow
    global lpulse
    global lastpulse
    global displaytext
    global kwhr
    global kwhrhigh
    global xneedle
    global yneedle
    global needlelength
    global plotkwhr
    global dayandtime
        
    solarLEDon()
    detected = time()
    lastpulse = detected - timenow
    lpulse = '{:0.2f}'.format(lastpulse)
    timenow = time()
    detect += 1
    kwhr = ('{:0.3f}'.format(3.600/(lastpulse)))
    kwhrlast = kwhr
    #kwhr = 3.6/lastpulse
    #kwhr = float (kwhr)
    #if kwhr < 4:
        #if float (kwhrlast) > float (kwhrhigh):
            #kwhrhigh = kwhrlast
    #print (kwhrlast)
    #print (kwhrhigh)
    redd=int(detect)
    dayandtime=datetime.now().strftime('%a %H:%M:%S')
    displaytext = (str(redd) + " - " + dayandtime + " @ " + kwhr + "kw").center (40," ")
    resultlog.insert(0.0, (displaytext + "\n"))
    root.after(100,solarLEDoff)
    kwhr = float (kwhr)
    sendoutputtofile()
    kwhrhigh = float (kwhrhigh)
    if kwhr < 4:
        drawpointer('black',70,3)
        drawbarchart()

# Send Output to file (This works well)
def sendoutputtofile():
    global dayandtime
    global detect
    global kwhr
    file = open('Solar Reading'+'.csv', 'a+')
    file.write ('\n')           
    file.write (str(detect))
    file.write (',')
    file.write (str(dayandtime))
    file.write (',')
    file.write (str(kwhr))
    file.close()
              
def solarLEDoff():
    MeterCanvas.create_oval(5, 5, 25, 25, width=0, fill='white')                

def solarLEDon():
    #MeterCanvas.create_rectangle(20, 20, 60, 60, width=0, fill='red')
    MeterCanvas.create_oval(5, 5, 25, 25, width=0, fill='blue')   

def whiteRectangle():
    MeterCanvas.create_rectangle(20, 20, 80, 80, width=0, fill='white')

def drawmeter():
    global kwhr
    global zerokwhr
    MeterCanvas.create_arc(20,20,180,180, outline = 'sky blue', width = 8, style = ARC, start = 0, extent = 180)
    MeterCanvas.create_text(7,97, text = '0')
    MeterCanvas.create_text(32,32, text = '1')
    MeterCanvas.create_text(100,10, text = '2')
    MeterCanvas.create_text(170,37, text ='3')
    MeterCanvas.create_text(193,97, text ='4')
    drawgraduations()
    drawpointerat0kw('black')
    drawunits()

def drawgraduations():
    MeterCanvas.create_line(100,20,100,22, width = 3) #2kw position (12 o'clock)
    MeterCanvas.create_line(180,98,180,96, width = 3) #4kw position (3 o'clock)
    MeterCanvas.create_line(20,97,20,95, width = 3)   #0kw position (9 o'clock)
    MeterCanvas.create_line(45,45,42,42, width = 3)   #1kw position (10:30 o'clock)
    MeterCanvas.create_line(160,45,157,45, width = 3) #3kw position (1:30 o'clock)

def drawpointerat0kw(colourr):
    removepointer()
    MeterCanvas.create_line(30,98,100,100, width = 3, fill = colourr)
    MeterCanvas.create_oval(110,110,90,90, fill = 'black') # Centre of dial

def drawpointerat2kw():
    removepointer()
    MeterCanvas.create_line(100,30,100,100, width = 3, fill = 'black')

def drawpointer(colourr,needlelength,widthh):
    global kwhr
    removepointer()
    if kwhr == 2:
        drawpointerat2kw()
    if kwhr < 2:
        xneedle = int(cos(radians (89) * kwhr/2) * needlelength)
        yneedle = int(sin(radians (89) * kwhr/2) * needlelength)
        MeterCanvas.create_line((100-xneedle),(100-yneedle),100,100, width = widthh, fill = colourr)
    if kwhr > 2:
        kwhr = (4 - kwhr)
        xneedle = int(cos(radians (89) * ((kwhr) /2)) * needlelength)
        yneedle = int(sin(radians (89) * ((kwhr) /2)) * needlelength)
        MeterCanvas.create_line((100+xneedle),(100-yneedle),100,100, width = widthh, fill = colourr)
    MeterCanvas.create_oval(110,110,90,90, fill = 'black') # Centre of dial

def drawpointerhigh(colourr,needlelength,widthh):
    global kwhr
    if kwhr == 2:
        drawpointerat2kw()
    if kwhr < 2:
        xneedle = int(cos(radians (89) * kwhrhigh/2) * needlelength)
        yneedle = int(sin(radians (89) * kwhrhigh/2) * needlelength)
        MeterCanvas.create_line((100-xneedle),(100-yneedle),100,100, width = widthh, fill = colourr)
    if kwhr > 2:
        kwhr = 4 - kwhr
        xneedle = int(cos(radians (89) * ((kwhrhigh) /2)) * needlelength)
        yneedle = int(sin(radians (89) * ((kwhrhigh) /2)) * needlelength)
        MeterCanvas.create_line((100+xneedle),(100-yneedle),100,100, width = widthh, fill = colourr)
    MeterCanvas.create_oval(110,110,90,90, fill = 'black') # Centre of dial    

def drawbarchart():
    global detect
    global fullscale
    BarChartCanvas.create_line(5,18,315,18, width = 1, fill = 'black')
    BarChartCanvas.create_line((fullscale/6),15,(fullscale/6),18, width = 1, fill = 'black')
    BarChartCanvas.create_line((fullscale*2/6),15,(fullscale*2/6),18, width = 1, fill = 'black')
    BarChartCanvas.create_line((fullscale*3/6),15,(fullscale*3/6),18, width = 1, fill = 'black')
    BarChartCanvas.create_line((fullscale*4/6),15,(fullscale*4/6),18, width = 1, fill = 'black')
    BarChartCanvas.create_line((fullscale*5/6),15,(fullscale*5/6),18, width = 1, fill = 'black')
    BarChartCanvas.create_line((315/30000*breakeven),15,(315/30000*breakeven),21, width = 1, fill = 'light green')
    BarChartCanvas.create_line((fullscale),15,(fullscale),18, width = 1, fill = 'black')
    if detect < breakeven:
        BarChartCanvas.create_line(5,8,(detect*315/30000),8, width = 7, fill = 'DeepPink')
    else:
        BarChartCanvas.create_line(5,8,(detect*315/30000),8, width = 7, fill = 'light green')
    BarChartCanvas.create_line(5,8,5,18, width = 1, fill = 'black')

def removepointer():
    MeterCanvas.create_oval(25,25,175,175, fill = 'white', outline = 'white')
    drawunits()
        
def drawunits():    
    MeterCanvas.create_text(100,70,font = 50, text = 'kwhr')

def displaygridlines():
    removepointer()

def printhighkwhrvalue():
    print ('High kwhr Value = ', kwhrhigh)

def resethighkwhrvalue():
    global kwhrhigh
    kwhrhigh = 0
    
# These next lines define size, position and title of tkinter window
root.geometry('350x550+20+150') # width x height + xpos + ypos
root.title("Solar Panel with Meter")

# event to detect falling pulse
GPIO.add_event_detect(10, GPIO.FALLING, callback=flashLED,bouncetime = 100)

#Frame and its contents
mainFrame = Frame(root, width=200, height = 200)
mainFrame.grid(row=0, column=0, padx=10, pady=2)

MeterCanvas = Canvas(mainFrame, width=200, height=125, bg='white')
MeterCanvas.grid(row=0, column=0, padx=10, pady=10)

BarChartCanvas = Canvas(mainFrame, width=320, height=30, bg='white')
BarChartCanvas.grid(row=1, column=0, padx=5, pady=5)

btnFrame = Frame(mainFrame, width=200, height = 200)
btnFrame.grid(row=2, column=0, padx=10, pady=2)

resultlog = Text(mainFrame, width = 40, height = 15, takefocus=0)
resultlog.grid(row=4, column=0, padx=10, pady=25)

#Btntemp = Button(btnFrame, text="0 kw", command=drawpointerat0kw)
#Btntemp.grid(row=0, column=0, padx=2, pady=2)

Btn02 = Button(btnFrame, text="Reset High kwhr Value", command=resethighkwhrvalue)
Btn02.grid(row=2, column=0, padx=2, pady=2)

#Btn04 = Button(btnFrame, text="4 kw", command=drawpointerat4kw)
#Btn04.grid(row=0, column=4, padx=2, pady=2)

#Btn01 = Button(btnFrame, text="1 kw", command=drawpointerat1kw)
#Btn01.grid(row=0, column=1, padx=2, pady=2)

#Btn03 = Button(btnFrame, text="3 kw", command=drawpointerat3kw)
#Btn03.grid(row=0, column=3, padx=2, pady=2)

Btntemp2= Button(btnFrame, text="Test", command=flashLED)
Btntemp2.grid(row=2, column=1, padx=2, pady=2)

#Btn02a = Button(btnFrame, text="2", command=drawpointerat2kw)
#Btn02a.grid(row=1, column=3, padx=2, pady=2)

Btnclear2 = Button(btnFrame, text="Clear", command=removepointer)
Btnclear2.grid(row=3, column=1, padx=2, pady=2)

#Btn01a = Button(btnFrame, text="1", command=drawpointerat1kw)
#Btn01a.grid(row=1, column=2, padx=2, pady=2)

BtnGrid = Button(btnFrame, text= "Print High kwhr Value", command=printhighkwhrvalue)
BtnGrid.grid(row=3, column=0, padx=2, pady=2)

#Lbl01 = Label(Canvas, text = str(kwhr))
#Lbl01.grid(row=1, column = 0, padx=0,pady=0)


drawmeter()
root.mainloop()

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

Re: Running a Procedure from a tkinter button or an event

Thu Feb 15, 2018 9:28 pm

The issue is that a GPIO callback event passes the channel of the GPIO pin as an argument to the callback function.
Summary: GPIO Callback passes 1 parameter

Now the tkinter button press callback does not pass any arguments
Summary: Tkinter 0 parameters

My proposed solution is that you have the GPIO callback and tkinter button call two separate functions.
I've provided my proposed changes in the snippets below

Your existing flashLED without the self.

Code: Select all

def flashLED(): # put self within brackets when operating from light sensor
    global detect
    global detected
New function

Code: Select all

def fallingPulseLED(channel):
    flashLED()
Change the callback to point to the new function

Code: Select all

# event to detect falling pulse
GPIO.add_event_detect(10, GPIO.FALLING, callback=fallingPulseLED,bouncetime = 100)
This part stays the same

Code: Select all

Btntemp2= Button(btnFrame, text="Test", command=flashLED)
Btntemp2.grid(row=2, column=1, padx=2, pady=2)
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

User avatar
Paeryn
Posts: 2108
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: Running a Procedure from a tkinter button or an event

Fri Feb 16, 2018 12:26 am

No need to create a separate function to do the same thing just because one way passes a parameter and the other doesn't. You could do it a couple of other ways (probably more knowing Python), in both examples I use None as the value to pass for when the button is pressed since your flashLED() function doesn't use the value anyway.

1) Define the parameter that flashLED takes as having a default value so when it gets called by the button without a parameter it is automatically given the default

Code: Select all

def flashLED(self=None):
2) Keep the function definition as you have it and use a lambda function to call flashLED() with a value when registering the callback for the button. Lambda functions are anonymous functions return the result of the given expression.

Code: Select all

Btntemp2= Button(btnFrame, text="Test", command=lambda : flashLED(None))
Lambda functions may look a bit odd but are really useful, if the expression needs parameters you list them before the colon (but don't put brackets around them), the expression after the colon is what will be evaluated when the lambda is called. The above line roughly translates to :-

Code: Select all

def temporary_flashLED():
    return flashLED(None)

Btntemp2= Button(btnFrame, text="Test", command=temporary_flashLED)

Also your drawing code is going to run into problems very quickly. You create objects on the canvas to draw the pointer, grid etc but when you want to draw the pointer in a new position you create more objects on top to blank out the originals and redraw new ones. The problem with that is all those objects you covered up are still there and they will all get drawn every time even though you've put other objects over the top of them. What you should really be doing is create the objects once keeping a record of the object ids, then when you want to update the position you can just alter its coordinates with coords() or change any of its properties like fill colour with itemconfig(). When modifying an object's properties it will stay in the same order of drawing (unless you change that property) so no need to re-draw objects that it either obscures or is obscured by.

Code: Select all

MeterCanvas = Canvas(mainFrame, width=200, height=125, bg='white')
MeterCanvas.grid(row=0, column=0, padx=10, pady=10)
# Create the meter's objects (I've only put the pointer here)
MeterPointer = MeterCanvas.create_line(30, 98, 100, 100, width = 3, fill = 'black')

def drawpointerat0kw(colourr):
    # Changing an object's coordinates
    MeterCanvas.coords(MeterPointer, 30,98, 100,100)
    # Changing any other property
    MeterCanvas.itemconfig(MeterPointer, fill = colourr)
    
# If you ever need to really remove an object from a canvas you can delete it
MeterCanvas.delete(MeterPointer)
She who travels light — forgot something.

RDS
Posts: 636
Joined: Tue Oct 06, 2015 8:17 am
Location: Lancashire, UK

Re: Running a Procedure from a tkinter button or an event

Fri Feb 16, 2018 9:49 am

@scotty101
Thank you that does exactly what I wanted.

@Paeryn
Thank you for a very comprehensive response.
I will look at the lamda comment later but for now the solution suggested by scotty works fine.
You comments regarding the drawing of the meter are very interesting. I was quite proud of the fact that I had created a meter and it appeared to work well until a lot of pulses (over 1000 I think) had been counted and then it went haywire. I calculate the kwhr figure by knowing the time between pulses and this works well to start with and then it starts to come up with some ridiculously high figures. To start with these are about every 10th pulse but then they get down to every other pulse. This then affects the meter drawing. Stopping my program and then restarting it, solves the problem until the same sort of problem re-occurs again after the same sort of pulses.
I wondered if it was some sort of loop that I had created in my program. I will study what you have said about co-ordinates and hopefully it will fix the problem.

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

Re: Running a Procedure from a tkinter button or an event

Fri Feb 16, 2018 2:27 pm

Following on from Paeryn's comments about your gauges, I've dug out an old example of a tkinter gauge I created back.

It updates the pointer''s coordinates rather than deleting or drawing over the top.

Its not very neat but I may update this post with a cleaner example. Currently the gauge just moves between 0 and 100% based on a slider.

Code: Select all

#Gauge.py

import tkinter as tk
import math

def limit(value,min_,max_):
    if value > max_:
        return max_
    elif value < min_:
        return min_
    else:
        return value

class Gauge(tk.Frame):
    def __init__(self,master=None,**kw):
        self.radius = radius = kw.pop('radius',50)
        tk.Frame.__init__(self,master=master,**kw)
        
        self.arrowsize = radius - 5
        padding = 30
        centre = 50
        y_start = 50
        self.canvas = c = tk.Canvas(self, width=radius*2+(padding*2), height=radius+padding+5)
        self.canvas.grid()
        self.arc = c.create_oval(padding, padding, (radius*2)+padding, (radius*2)+padding)
        self.canvas.itemconfig(self.arc,fill='white')
        
        self.pointer_x1 = pointer_x1 = radius + padding
        self.pointer_y1 = pointer_y1 = radius + padding
        self.pointer_x2 = pointer_x2 = radius + self.arrowsize
        self.pointer_y2 = pointer_y2 = radius

        self.pointer = c.create_line(pointer_x1,
                                     pointer_y1,
                                     pointer_x2,
                                     pointer_y2,
                                     fill='blue',
                                     arrow=tk.LAST,
                                     width=2)

        for i in range(0,110,10):
            self.place_tick(i)

    def set_value(self, percentage):
        percentage = limit(percentage,0,100)
        #Convert percentage to angle
        # 90deg = 0%, 0deg = 50%, -90deg = 100%
        # calculated using y = mx+c
        angle = -1.8 * percentage + 90
        distance = self.arrowsize
        x1 = self.pointer_x1
        y1 = self.pointer_y1
        x2 = x1 - distance * math.sin(math.radians(angle))
        y2 = y1 - distance * math.cos(math.radians(angle))
        self.canvas.coords(self.pointer,x1,y1,x2,y2)

    def place_tick(self, percentage):
        c = self.canvas
        percentage = limit(percentage,0,100)
        angle = -1.8 * percentage + 90
        ticksize = 5
        x = self.pointer_x1
        y = self.pointer_y1
        x1 = x - self.radius * math.sin(math.radians(angle))
        y1 = y - self.radius * math.cos(math.radians(angle))
        x2 = x - (self.radius+ticksize) * math.sin(math.radians(angle))
        y2 = x - (self.radius+ticksize) * math.cos(math.radians(angle))
        
        print(x1,y1,x2,y2)
        tick = c.create_line(x1,
                             y1,
                             x2,
                             y2,
                             fill='red',
                             width=5)

        textsize = 15
        txt_x2 = x - (self.radius+textsize) * math.sin(math.radians(angle))
        txt_y2 = x - (self.radius+textsize) * math.cos(math.radians(angle))
        
        text = c.create_text(txt_x2,txt_y2,text=str(percentage))

def moveGauge(e):
    gauge.set_value(slider.get())

if __name__ == '__main__':
    root = tk.Tk()
    gauge = Gauge(root,radius=100)
    gauge.grid()
    slider = tk.Scale(root,
                      from_=0.0,
                      to=150.0,
                      orient=tk.HORIZONTAL,
                      command=moveGauge)
    slider.grid()
    root.mainloop()

Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

RDS
Posts: 636
Joined: Tue Oct 06, 2015 8:17 am
Location: Lancashire, UK

Re: Running a Procedure from a tkinter button or an event

Sat Feb 17, 2018 7:42 pm

I have made the changes to my program regarding the pointer and using coords rather than just re-drawing the pointer each time.

Thinking about it, I assume this this same policy will apply to my barchart where I currently just draw a longer line, without removing the last one.
Presumably, this should also be done using the coords method?

User avatar
Paeryn
Posts: 2108
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: Running a Procedure from a tkinter button or an event

Sat Feb 17, 2018 9:46 pm

Yes, wherever you are redrawing things that are already drawn you are better off moving / updating the original object (it will stay in the same place in the drawing stack so you don't have to worry about objects above or below it), or delete the original and create a new one (but that will require you to put it in the same place in the drawing stack unless it was on the top of the stack). Any object that doesn't change never needs recreating.

Whenever part of a canvas needs to update what it shows (e.g. something changes or another window above moved revealing part of the canvas) the canvas will go through all the objects that are on its draw stack in order from the lowest to the highest and any that are totally or partially within the area affected will be drawn to that area. The canvas isn't a bitmap that you are drawing onto with new objects overwriting what was already there, its more like a table and each object you create is a separate transparent sheet with the object drawn onto it and the sheet is placed on the table. If you keep adding objects just to cover up what is underneath you will end up with a very unwieldy thick picture full of things you can't see.

The canvas doesn't know if one object fully obscures what is below it so it has to process every layer each time it need to update.
She who travels light — forgot something.

RDS
Posts: 636
Joined: Tue Oct 06, 2015 8:17 am
Location: Lancashire, UK

Re: Running a Procedure from a tkinter button or an event

Sat Feb 17, 2018 10:57 pm

Thank you for that. I am using up a lot of unnecessary processing time.

RDS
Posts: 636
Joined: Tue Oct 06, 2015 8:17 am
Location: Lancashire, UK

Re: Running a Procedure from a tkinter button or an event

Sun Feb 18, 2018 7:03 pm

I have made some more changes today, having realised that I was drawing the Meter each time I called it.
Having completed the Meter changes, it has occurred to me that I create the flashing LED by drawing it blue and then white (the colour of the background).

RDS
Posts: 636
Joined: Tue Oct 06, 2015 8:17 am
Location: Lancashire, UK

Re: Running a Procedure from a tkinter button or an event

Tue Feb 20, 2018 5:26 pm

@Paeryn
I just wanted to say thank you again for your post on the 16th Feb, advising me about how my drawing method would quickly run into problems. Following your post and advice, I altered my program to use coords, for drawing the meter pointer, the flashing LED and the Barchart. I also changed the meter drawing portion because I had been drawing the actual meter again each time, rather than just at the beginning.

Today has been a nice sunny day here and the counter has recorded over 17,000 pulses, without a single failure. Before the changes it failed miserably after about 1,000.

Thanks again.

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

Re: Running a Procedure from a tkinter button or an event

Tue Feb 20, 2018 5:57 pm

I'm sure I told you about that too in the example I provided before.

viewtopic.php?f=91&t=203759&p=1265081#p1265053
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

User avatar
Paeryn
Posts: 2108
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: Running a Procedure from a tkinter button or an event

Tue Feb 20, 2018 6:07 pm

No worries RDS, I'm glad it's working fine for you now.
She who travels light — forgot something.

RDS
Posts: 636
Joined: Tue Oct 06, 2015 8:17 am
Location: Lancashire, UK

Re: Running a Procedure from a tkinter button or an event

Tue Feb 20, 2018 7:16 pm

scotty101 wrote:
Tue Feb 20, 2018 5:57 pm
I'm sure I told you about that too in the example I provided before.

viewtopic.php?f=91&t=203759&p=1265081#p1265053
Oh Yes. Very sorry scotty. That part of your reply had escaped me. I did use the 'after' command but I had not appreciated the importance of the other part of your reply. After all the help you have given me as well - I may not use the 'class' examples any more but you really helped me get started with tkinter.

Return to “Beginners”

Who is online

Users browsing this forum: Baidu [Spider], markost and 32 guests