0

I am trying to get a Tkinter window to change a label based on temperature probe readings. I have found some people who have done similar but my code doesn't seem to work. Instead the Tkinter window hangs. The code seems to continue looping and printing output to terminal, just Tkinter doesn't work.

Any ideas? I apologise for my poor code layout. I've only been learning python/coding for a few weeks.

from random import randint
import time
import tkinter as tk
import tkinter.font as tkfont


def tempprobe():
    while True:
        tempsimsum = 0
        for count in range(4):
            # This is to simulate temperature probe readings. 4 per second. Takes 4 readings then finishes loop
            tempsimraw = randint(14, 30)
            time.sleep(0.25)
            tempsimsum = tempsimsum + tempsimraw

        global temperature
        global temperatureWindow
        temperature.set(value=tempsimsum / 4)   # Averaging so lessen noise and spikes
        print(temperature.get())
        # This should 'refresh' labeltemperature in the tk window and restart this function but it just hangs the window
        temperatureWindow.after(500, tempprobe())


temperatureWindow = tk.Tk()

dfont = tkfont.Font(size=-24)

temperature = tk.DoubleVar()
labeltemperature = tk.Label(textvariable=temperature, font=dfont)
labeltemperature.pack()
buttonstart = tk.Button(text='Start',
                    font=dfont,
                    command=tempprobe)
buttonstart.pack()

temperatureWindow.mainloop()

2 Answers2

0
from random import randint
import time
import tkinter as tk
import tkinter.font as tkfont


def tempprobe():
    tempsimsum = 0
    for count in range(4):
        # This is to simulate temperature probe readings. 4 per second. Takes 4 readings then finishes loop
        tempsimraw = randint(14, 30)
        time.sleep(0.25)
        tempsimsum = tempsimsum + tempsimraw

    global temperature
    global temperatureWindow
    temperature.set(value=tempsimsum / 4)   # Averaging so lessen noise and spikes
    print(temperature.get())
    # This should 'refresh' labeltemperature in the tk window and restart this function but it just hangs the window
    temperatureWindow.after(500, tempprobe)


temperatureWindow = tk.Tk()

dfont = tkfont.Font(size=-24)

temperature = tk.DoubleVar()
labeltemperature = tk.Label(textvariable=temperature, font=dfont)
labeltemperature.pack()
buttonstart = tk.Button(text='Start',
                    font=dfont,
                    command=tempprobe)
buttonstart.pack()

temperatureWindow.mainloop()
Ayyoub ESSADEQ
  • 776
  • 2
  • 14
0

Don't use while because it blocks mainloop() and it can't get events from system, etc. and it can't redraw window - so it freezes.

You should use only after(10, tempprobe) to repeate it.

But after() needs function's name without () (like command= or bind())


Full code with other changes and only with my comments.

from random import randint
import time
import tkinter as tk

# --- functions ---

def tempprobe():
    # all `global` at the beginning of function
    #global temperature         # you don't need `global` if you don't use `=` to assign new value
    #global temperature_window  # you don't need `global` if you don't use `=` to assign new value
    
    tempsimsum = 0

    for count in range(4):
        tempsimraw = randint(14, 30)
        time.sleep(0.25)
        tempsimsum += tempsimraw

    temperature.set(tempsimsum / 4)
    print(temperature.get())
    
    temperature_window.after(500, tempprobe)  # without `()`


# --- main ---

temperature_window = tk.Tk()  # PEP8: `lower_case_names` for variables

temperature = tk.DoubleVar(temperature_window)

# every widget should have `parent` as first value
label_temperature = tk.Label(temperature_window, textvariable=temperature)  
label_temperature.pack()

# every widget should have `parent` as first value
button_start = tk.Button(temperature_window, text='Start', command=tempprobe)
button_start.pack()

temperature_window.mainloop()

PEP 8 -- Style Guide for Python Code


But problem makes also sleep(0.25) which also blocks mainloop() and this need more complex change.

I would use list to keep values. If I would get 4 values then I could calculate temperature, clear list and make longer delay - 500ms. If I would have less values then I would add make shorter delay - 250ms.

from random import randint
import time
import tkinter as tk

# --- functions ---

last_values = []

def tempprobe():

    tempsimraw = randint(14, 30)
    last_values.append(tempsimraw)

    if len(last_values) == 4:
        tempsimsum = sum(last_values)
        temperature.set(tempsimsum / 4)
        print(temperature.get())

        last_values.clear()  # remove all values
        
        temperature_window.after(500, tempprobe)
    else:
        temperature_window.after(250, tempprobe)


# --- main ---

temperature_window = tk.Tk()  # PEP8: `lower_case_names` for variables

temperature = tk.DoubleVar(temperature_window)

# every widget should have `parent` as first value
label_temperature = tk.Label(temperature_window, textvariable=temperature)  
label_temperature.pack()

# every widget should have `parent` as first value
button_start = tk.Button(temperature_window, text='Start', command=tempprobe)
button_start.pack()

temperature_window.mainloop()
furas
  • 134,197
  • 12
  • 106
  • 148
  • Wow. Thankyou very much. Thankyou for the `while` tip. += is a LOT cleaner than var = var +var2 Using a list seems like it'll be easier to add to later. Is using a list for this considered better practice? Why do you suggest 500ms wait after refreshing the window? Is that to give more time to view the output on screen? Is the parent as first value in a widget for an efficiency reason, or because it's cleaner code? – Billy Woods May 25 '22 at 03:52
  • I used 500ms because you used 500ms in your `after()` - so I tried to get the same effect. Normallly I would use only one `after()` wotj 250ms. I was thinking also about different method to calculate temperature. I would add new temperature to list and at once calculate average value using last 4 values from list. I add partent because to make code cleaner. And using parent you can put widget inside another widget (i.e. inside `Frame`) to group elements and to create own widget. Beside if you would have two windows then you have to use parent to put it in correct window. – furas May 25 '22 at 10:18