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