Search code examples
pythontkinterdelaygpio

Need help finding a solution to tkinter with gpio and after method


I'm working on a project in tkinter that is a questionnaire. If you answer correctly it takes you to a end page where it prompts you to press a button. Once You hit that button I need the GPIO pin to set to high and hold for a duration and then switch back to low. After that it then takes you back to the main page to start the questionnaire over again.

I started with the time.sleep function to hold the pin high which I've learned is not good to use for GUI's. It does work for me despite that but through testing it I found that while it's sleeping for the duration the button will still take button presses and seems to buffer them which seems to stack on after the first button press is made.

After doing some searches I found the after method and I've tried implementing that and it seems to do something very similar. I'd like to make the program as foolproof as possible so if someone is impatient and hits the button twice it won't extend the duration and make it lock up.

I've also looked in to trying to disable the button after a press but I can't seem to get it to work right.

Here is the window where It prompts you to press the button and then triggers the gpio to go high, wait for a duration then go low. It then switches it to the main page. I also have it moving the mouse so it doesn't hover over the button on the next page

class PleasePass(tk.Frame):
def __init__(self, parent, controller):
    tk.Frame.__init__(self, parent)

    label = tk.Label(self, text="Thank you \n Please press the button then proceed to tempature reading",
                     font=('Helvetica', 30))
    label.grid(column=0, row=0, padx=110, pady=200)

    button1 = tk.Button(self, text="Ready to Proceed", height=3, width=50, bg="lightgreen",
                        fg="black", font=('Helvetica', 20, "bold"),
                        command=lambda: [GPIO.output(26, GPIO.HIGH), self.after(2000),
                                         GPIO.output(26, GPIO.LOW),
                                         controller.show_frame(StartPage),
                                         self.event_generate('<Motion>', warp=True, x=50, y=50)])

    button1.grid(column=0, row=100)

I'd appreciate some help with this one. I'm just starting to learn how to use python and tkinter so my code is very copy paste and i'm sure very sloppy.


Solution

  • Don't put so much functionality into a lambda function directly. Write an additional method in your class:

    def clicked(self):
        self.button1.config(state="disabled") # disable button
        GPIO.output(26, GPIO.HIGH)
        self.after(2000, self.proceed) # call method proceed after 2 seconds
    
    def proceed(self):
        GPIO.output(26, GPIO.LOW)
        # additional stuff
    

    Now, in your __init__ method make button1 an instance variable with self.button1 = tk.Button(.... Finally, you can simply set the command parameter of your Button to your new method: command=self.clicked (without brackets).