Search code examples
pythontkintershufflekeypad

How to rename buttons when 'E' is pressed


Stolen from my previous post, this is the purpose of this post.

Bank vault systems that have a tactile number pad for pin entry are vulnerable to misuse by a thief. Thieves can use cameras, themselves, or even other people to view the pattern that a 4 digit pin makes when entered; therefore they do not need to know the actual value of your pin, just the sequence of button presses that will allow for entry into the system. To overcome this fatal flaw, a touchscreen display that has a number pad GUI may be used, with the keys being shuffled every time the pin is entered whether it is correct or not.

Im trying to shuffle the Keypad matrix every time a 'E' is received (which works), however the GUI refuses to update. Im trying to get the numbers and letters to shuffle any time a user enters their pin. Any help is appreciated.

#!/usr/bin/env python3

import Tkinter as tk
import random

def code(value):
    # inform function to use external/global variable
    global pin

    if value == 'D':
        # remove last element from `pin`
        pin = pin[:-1]
        # remove all from `entry` and put new `pin`
        e.delete('0', 'end')
        e.insert('end', pin)

    elif value == 'E':
         # check pin

       if pin == "3529":

        print("PIN OK")


       else:
            print("PIN ERROR!")
            # clear pin
            pin = ''
            e.delete('0', 'end')


    else:
        # add number to `pin`
        pin += value
        # add number to `entry`
        e.insert('end', value)

    print("Current:", pin)



# --- main ---

# keypad description
keys = [
['1', '2', '3'],
['4', '5', '6'],
['7', '8', '9'],
['D', '0', 'E'],
]



for key in keys:
    random.shuffle(key)
    random.shuffle(keys)
    print(keys)

# create global variable 
pin = '' # empty string

# init
root = tk.Tk()

# create `entry` to display `pin`
e = tk.Entry(root, justify='right')
e.grid(row=0, column=0, columnspan=3, ipady=5)

# create `buttons` using `keys
for y, row in enumerate(keys, 1):
    for x, key in enumerate(row):
        # `lambda` inside `for` have to use `val=key:code(val)`
        # instead of direct `code(key)`
        b = tk.Button(root, text=key, command=lambda val=key:code(val))
        b.grid(row=y, column=x, ipadx=20, ipady=20)

# start program

root.mainloop()

Solution

  • Change enumerate(keys, 1) to enumerate(keys) and b.grid(row=y, column=x, ipadx=20, ipady=20) to b.grid(row=y+1, column=x, ipadx=20, ipady=20) so that the entry can be displayed.

    Complete code:

    import tkinter as tk
    import random
    
    def code(position):
        global pin
        b = buttons[position]
        value = b['text']
    
        if value == 'D':
            # remove last element from `pin`
            pin = pin[:-1]
            # remove all from `entry` and put new `pin`
            e.delete('0', 'end')
            e.insert('end', pin)
    
        elif value == 'E':
            # check pin
            if pin == "3529":
                print("PIN OK")
            else:
                print("PIN ERROR!")
                # clear pin
                pin = ''
                e.delete('0', 'end')
        else:
            # add number to `pin`
            pin += value
            # add number to `entry`
            e.insert('end', value)
    
        print("Current:", pin)
    
        shuffle_buttons()
    
    def shuffle_buttons():
        for key in keys:
            random.shuffle(key)
        random.shuffle(keys)
        for y, row in enumerate(keys):
            for x, key in enumerate(row):
                b = buttons[(x, y)]
                b['text'] = key                
    
    # --- main ---
    
    # keypad description
    
    keys = [
        ['1', '2', '3'],
        ['4', '5', '6'],
        ['7', '8', '9'],
        ['D', '0', 'E'],
    ]
    
    buttons = {}
    
    # create global variable 
    pin = '' # empty string
    
    # init
    root = tk.Tk()
    
    # create `entry` to display `pin`
    e = tk.Entry(root, justify='right')
    e.grid(row=0, column=0, columnspan=3, ipady=5)
    
    # create `buttons` using `keys
    for y, row in enumerate(keys):
        for x, key in enumerate(row):
            position  = (x, y)
            b = tk.Button(root, text= key, command= lambda val=position: code(val))
            b.grid(row=y+1, column=x, ipadx=20, ipady=20)
    
            buttons[position] = b
    
    shuffle_buttons()
    
    root.mainloop()