3

I am currently creating a GUI with tkinter for a tilt table in my lab. I have up and down buttons programmed to turn a pin on until the table reaches a certain angle, which is read in from an inclinometer via Arduino, and then turn the pin off. So currently the function associated with each button repeatedly reads in the angle until the correct angle is reached, but I also want to be able to turn off the pin whenever I choose. The problem is that while the function associated with Up is running, the program is not checking for any button presses. How can I get the pause button to interrupt the function?

I've tried to implement interrupts with the threading library, but it seems tkinter won't let any other code run while the function associated with a button() is running.

import tkinter as tk
from tkinter import *
import RPi.GPIO as GPIO
import time
import serial
global read_serial

win = Tk()

def Up():
     if read_serial < target: 
          global read_serial  #read_serial is edited elsewhere not included here
          GPIO.output(40,GPIO.HIGH)
          time.sleep(.05)
          read_serial=ser.readline().rstrtip().decode("utf-8")
          read_serial=float(read_serial)
          Up()
     else:
          GPIO.otuput(40,GPIO.LOW)

def Pause():
     GPIO.output(40,GPIO.LOW)

upButton = Button(win,text='UP',command=Up)
pauseButton = Button(win,text='PAUSE',command=Pause)
upButton.grid(row=1)
pauseButton.grid(row=2)

win.mainloop()

I didn't want to paste too much code but if I'm missing any crucial parts I can include more. I want to interrupt Up() when I press Pause, but once I press Up, the program ignores any input until read_serial is greater than target. Is it possible to implement an interrupt to check for other button presses with tkinter?

martineau
  • 119,623
  • 25
  • 170
  • 301
BenS
  • 45
  • 1
  • 6
  • You have to use threading – Nouman Aug 28 '19 at 14:51
  • @BlackThunder Thread(target=?) would my target be Pause or pauseButton? – BenS Aug 28 '19 at 14:54
  • I don't use threadings so you have to figure it out yourself – Nouman Aug 28 '19 at 14:55
  • 2
    Threading isn't the only answer, but you *must* actually return from your button commands fairly quickly if the GUI is to remain responsive. Any ongoing activity could be performed in a thread, or done a little piece at a time in a function that you schedule later via `.after()` (and it can reschedule itself with `.after()` if the activity still isn't finished). – jasonharper Aug 28 '19 at 14:56
  • I think like @jasonharper suggested, the better idea would be to use ```.after()``` here instead of threading. – Joshua Nixon Aug 28 '19 at 14:58
  • @BlackThunder Ok, I tried using it already but it continued to ignore my button presses so I wasn't sure if it works with tkinter or not. Thanks though, I will try and see if I can get it to work. – BenS Aug 28 '19 at 14:59
  • @jasonharper This may be a dumb question, but the .after() would have to be in the mainloop, correct? That way it can return from the button command but still call back to it if necessary – BenS Aug 28 '19 at 15:05
  • BenS: I think you would find [Freezing/Hanging tkinter Gui in waiting for the thread to complete](https://stackoverflow.com/questions/53696888/freezing-hanging-tkinter-gui-in-waiting-for-the-thread-to-complete) helpful. – martineau Aug 28 '19 at 15:10
  • 2
    You could probably just use `win.after(0, Up)` instead of calling `Up()` directly. – tobias_k Aug 28 '19 at 15:42

1 Answers1

1

The easiest to run a function in the background when using tkinter is to use the .after() method, this allows for you not to need the threading module. The 0 in the .after() is the number of ms to wait until it executes the function given.

example (not the best way as it now has another function):

def bnt_up():
    win.after(0, Up)
upButton = Button(win,text='UP',command=bnt_up)
enchant97
  • 301
  • 3
  • 12