0

I am using the 4x4 membrane keypad with the raspberry pi to get the input from the keypad to be displayed onto an entry label using tkinter. I am using a thread to read the key presses on the keypad and putting the key presses into a queue, that will be read simultaneously by using tkinter after to call the read_queue function to get the key press from the queue and input it into an entry label.

I am trying to simulate a scenario where the keypad will be used more than once, but when I do, the read_queue function is being called more than once and causing the queue to have multiple entries of a key press, and having the entry label display the keys more than once. I am having trouble understanding how to fix this, so I would appreciate the help.

This is my code

from pad4pi import rpi_gpio
import time
import tkinter as tk
import sys
import RPi.GPIO as GPIO
import queue
import threading

inp = ""
q = queue.Queue()
PIN = "7797AA"
a = 0
            
class GUI(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        self.data = {
            "text": tk.StringVar()
        }

        container = tk.Frame(self)
        container.pack(side = "top", fill = "both", expand = "True")
        container.grid_rowconfigure(0, weight = 1)
        container.grid_columnconfigure(0, weight = 1)

        self.frames = {}
        for F in (Page_One, Accepted, Denied):
            page_name = F.__name__
            frame = F(parent = container, controller = self)
            self.frames[page_name] = frame

            frame.grid(row = 0, column = 0, sticky = "nsew")
        self.show_frame("Page_One")
    def show_frame(self, page_name):
        '''Show a frame '''
        frame = self.frames[page_name]
        frame.tkraise()

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

        self.label = tk.Entry(self, textvariable = self.controller.data["text"])
        self.label.place(x=200, y = 300)
        
        button = tk.Button(self, text = "Use External Keypad", command = lambda: self.thre())
        button.pack()
        
    def thre(self):
        self.t1 = threading.Thread(target = self.Keypad)
        self.run = True
        if self.run and not self.t1.is_alive():
            try:
                self.t1.start()
                self.controller.after(100, self.read_queue)
            except RuntimeError:
                self.t1 = threading.Thread(target = self.Keypad)
                self.t1.start()
        
    def read_queue(self):
        if q.empty():
            self.controller.after(100, self.read_queue)
        else:
            val = q.get(0)
            self.label.insert('end', val)
            print("Value in queue: ", val)
            self.controller.after(200, self.read_queue)
            
    def Keypad(self):
        def accept(self):
            self.controller.show_frame("Accepted")
            self.t1.join()
            self.run = False
        def den(self):
            self.controller.show_frame("Denied")
            self.t1.join()
            self.run = False
        def home(self):
            self.controller.show_frame("Page_One")
        KEYPAD = [
            ["1","2","3","A"],
            ["4","5","6","B"],
            ["7","8","9","C"],
            ["*","0","#","D"]
            ]
        
        GPIO.setwarnings(False)
        # same as calling: factory.create_4_by_4_keypad, still we put here fyi:
        ROW_PINS = [5, 6, 13, 19] # BCM numbering; Board numbering is: 7,8,10,11 (see pinout.xyz/)
        COL_PINS = [12, 16, 20, 21] # BCM numbering; Board numbering is: 12,13,15,16 (see pinout.xyz/)
        
        factory = rpi_gpio.KeypadFactory()

        keypad = factory.create_keypad(keypad=KEYPAD, row_pins=ROW_PINS, col_pins=COL_PINS)
        
        def keypress(key):
            global a
            global inp
            if (key =='*'):
                print("Input reset")
                inp = ""
                with q.mutex:
                    q.queue.clear()
                self.label.delete(0, tk.END)
                a+=1
            elif (key == '#'):
                if a ==4:
                    print("Too many tries")
                    self.controller.after(100, den(self))
                    self.controller.after(5000, home(self))
                    keypad.cleanup()
                    with q.mutex:
                        q.queue.clear()
                    self.label.delete(0, tk.END)
                if inp == PIN:
                    self.label.delete(0, tk.END)
                    self.controller.after(100, accept(self))
                    self.controller.after(5000, home(self))
                    inp = ""
                    keypad.cleanup()
                    with q.mutex:
                        q.queue.clear()
                else:
                    print("Passcode incorrect")
                    inp = ""
                    a += 1
                    with q.mutex:
                        q.queue.clear()
                    self.label.delete(0, tk.END)
            else:
                print(key)
                inp = inp + key
                q.put(key)
        keypad.registerKeyPressHandler(keypress)

if __name__ == '__main__':
    app = GUI()
    app.geometry("1000x600")
    app.mainloop()   

Edit: Took out the Accepted and Denied frames

Darth_Yoda
  • 37
  • 3
  • please provide [mre] – Matiiss Apr 22 '21 at 20:39
  • Instead of `.after(, (...))` use `.after(, lambda: (...))` – TheLizzard Apr 22 '21 at 20:43
  • Do I use it for all `.after`, or only the ones that call the `read_queue` function? – Darth_Yoda Apr 22 '21 at 20:44
  • `after` requires a [callable](https://stackoverflow.com/questions/111234/what-is-a-callable) – Bryan Oakley Apr 22 '21 at 21:14
  • `after` similar to `thread`, `command=` and `bind` needs function's name without `()`. And later it uses `()` to run it with delay. If you need to use function with arguments then you could use `after( ..., lambda:func(arg1, arg2))` or better `after( ..., func, arg1, arg2)` – furas Apr 22 '21 at 22:05

0 Answers0