pythontkintervirtual-keyboard

Typing on entry using virtual keyboard in another python program


I'm having a problem with typing into my Tkinter entry. I did a registration code and with every entry on my code calls a virtual keyboard, the virtual keyboard is separated python program. I successfully called another python program but I can't type on my Tkinter entry which is my main program using the virtual keyboard I called. Is there any way to get this done? here is my code

    def register(self):
    self.master_register = Toplevel()

    self.first_name = StringVar()
    self.middle_name = StringVar()
    self.last_name = StringVar()
    self.sex = StringVar()
    self.birth_day = StringVar()
    self.civil_status = StringVar()

    self.label_head = Label(self.master_register, text = "Please fill up all informations below")
    self.label_head.pack()

    self.label_first_name = Label(self.master_register, text = "First Name")
    self.label_first_name.pack()
    self.entry_first_name = Entry(self.master_register, textvariable = self.first_name)
    self.entry_first_name.pack()
    self.entry_first_name.bind('<ButtonPress-1>',self.keyboard)

    self.label_middle_name = Label(self.master_register, text = "Middle Name")
    self.label_middle_name.pack()
    self.entry_middle_name = Entry(self.master_register, textvariable = self.middle_name)
    self.entry_middle_name.pack()
    self.entry_middle_name.bind('<ButtonPress-1>',self.keyboard)

    self.label_last_name = Label(self.master_register, text = "Last Name")
    self.label_last_name.pack()
    self.entry_last_name = Entry(self.master_register, textvariable = self.last_name)
    self.entry_last_name.pack()
    self.entry_last_name.bind('<ButtonPress-1>',self.keyboard)

    self.label_sex = Label(self.master_register, text = "Sex")
    self.label_sex.pack()
    self.radio_button_sex1 = Radiobutton(self.master_register, text = "Male", variable = self.sex, value = "Male" )
    self.radio_button_sex1.pack()
    self.radio_button_sex2 = Radiobutton(self.master_register, text = "Female", variable = self.sex, value = "Female")
    self.radio_button_sex2.pack()


    self.label_birthday = Label(self.master_register, text = "Birth Day")
    self.label_birthday.pack()
    self.entry_birthday = Entry(self.master_register, textvariable = self.birth_day)
    self.entry_birthday.pack()
    self.entry_birthday.bind('<ButtonPress-1>',self.keyboard)

    self.label_civil_status = Label(self.master_register, text = "Civil Status")
    self.label_civil_status.pack()
    self.entry_civil_status = Entry(self.master_register, textvariable = self.civil_status)
    self.entry_civil_status.pack()
    self.entry_civil_status.bind('<ButtonPress-1>',self.keyboard)

    self.button_submit = Button(self.master_register, text = "Submit", command = lambda: self.registered(self.first_name, self.middle_name,
                                                                                        self.last_name, self.sex, self.birth_day,
                                                                                        self.civil_status))
    self.button_submit.pack()

def keyboard(self, event):
    exec(open("keyboardclass.py").read());

here is my keyboardclass.py

def select(value):
if value == "Space":
    entry1.insert(tkinter.END, ' ')
elif value == "Backspace":
    entry1.delete(len(entry1.get())-1,tkinter.END)
else:
    entry1.insert(tkinter.END, value)

root = Tk()
root.configure(background = "cornflowerblue")
root.wm_attributes("-alpha", 0.7)

alphabets = ['`','1','2','3','4','5','6','7','8','9','0','-','=','<- 
   Backspace',
        'Tab','q','w','e','r','t','y','u','i','o','p','[',']',"\\",
        'Caps Lock','a','s','d','f','g','h','j','k','l',';',"'",'Enter',
        'Shift','z','x','c','v','b','n','m',',','.','/','Shift',
         'Space']
Row = 2
Column = 0

for alphabet in alphabets:
command = lambda x=alphabet: select(x)
if alphabet != 'Space':
    Button(root, text = alphabet,
           command = command,width = 5, padx=3, pady=3,bd=12,bg = "black", fg="white").grid(row = Row, column = Column)
if alphabet == 'Enter':
    Button(root, text = alphabet,
           command = command, width = 15, padx=3, pady=3,bd=12,bg = "black", fg="white").grid(row = Row, column = Column, columnspan = 2)
if alphabet == 'Shift':
    Button(root, text = alphabet,
           command = command, width = 15, padx=3, pady=3,bd=12,bg = "black", fg="white").grid(row = Row, column = Column, columnspan = 2)    
if alphabet == 'Space':
    Button(root, text = alphabet,
           command = command, width = 130, padx=3, pady=3,bd=12,bg = "black", fg="white").grid(row = 6, columnspan = 16)

Column +=1
if Column > 13 and Row == 1:
    Column = 0
    Row += 1
if Column > 13 and Row == 2:
    Column = 0
    Row +=1
if Column > 13 and Row == 3:
    Column = 0
    Row +=1
if Column > 12 and Row == 4:
    Column = 0
    Row +=1

root.mainloop()


Solution

  • keyboard.py

    I put code in function create() which gets root and entry as arguments - so now I can use import keyboard it other file and run keyboard.create(root, some_entry).

    It uses root to create window Toplevel() instead of Tk() - and without second mainloop().

    It uses entry to use it in select(entry, value) which will use entry.insert(...)

    There is code in if __name__ == "__main__": so you can run it as standalone program to test keyboard.

    It displays two Entry and one Text (in which you can test key Enter).

    I added code for Enter, Tab, Backspace for Text (which needs different method). When you press Shift or Caps Lock then it starts to insert uppercase chars - but it doesn't change text on buttons in window.

    In alphabets I grouped rows in lists so I don't need if/else to check if char should be in next row - I can use two for-loops.


    import tkinter as tk
    
    alphabets = [
        ['`','1','2','3','4','5','6','7','8','9','0','-','=','Backspace'],
        ['Tab','q','w','e','r','t','y','u','i','o','p','[',']',"\\"],
        ['Caps Lock','a','s','d','f','g','h','j','k','l',';',"'",'Enter'],
        ['Shift','z','x','c','v','b','n','m',',','.','/','Shift'],
        ['Space']
    ]    
    
    uppercase = False  # use uppercase chars. 
    
    def select(entry, value):
        global uppercase
    
        if value == "Space":
            value = ' '
        elif value == 'Enter':
            value = '\n'
        elif value == 'Tab':
            value = '\t'
    
        if value == "Backspace":
            if isinstance(entry, tk.Entry):
                entry.delete(len(entry.get())-1, 'end')
            #elif isinstance(entry, tk.Text):
            else: # tk.Text
                entry.delete('end - 2c', 'end')
        elif value in ('Caps Lock', 'Shift'):
            uppercase = not uppercase # change True to False, or False to True
        else:
            if uppercase:
                value = value.upper()
            entry.insert('end', value)
    
    def create(root, entry):
    
        window = tk.Toplevel(root)
        window.configure(background="cornflowerblue")
        window.wm_attributes("-alpha", 0.7)
    
        for y, row in enumerate(alphabets):
    
            x = 0
    
            #for x, text in enumerate(row):
            for text in row:
    
                if text in ('Enter', 'Shift'):
                    width = 15
                    columnspan = 2
                elif text == 'Space':
                    width = 130
                    columnspan = 16
                else:                
                    width = 5
                    columnspan = 1
    
                tk.Button(window, text=text, width=width, 
                          command=lambda value=text: select(entry, value),
                          padx=3, pady=3, bd=12, bg="black", fg="white"
                         ).grid(row=y, column=x, columnspan=columnspan)
    
                x += columnspan
    
    # --- main ---
    
    if __name__ == '__main__':
        root = tk.Tk()
        root.title('Test Keyboard')
    
        label = tk.Label(root, text='Test Keyboard')
        label.grid(row=0, column=0, columnspan=2)
    
        entry1 = tk.Entry(root)
        entry1.grid(row=1, column=0, sticky='news')
    
        button1 = tk.Button(root, text='Keyboard', command=lambda:create(root, entry1))
        button1.grid(row=1, column=1, sticky='news')
    
        entry2 = tk.Entry(root)
        entry2.grid(row=2, column=0, sticky='news')
    
        button2 = tk.Button(root, text='Keyboard', command=lambda:create(root, entry2))
        button2.grid(row=2, column=1, sticky='news')
    
        text1 = tk.Text(root)
        text1.grid(row=3, column=0, sticky='news')
    
        button3 = tk.Button(root, text='Keyboard', command=lambda:create(root, text1))
        button3.grid(row=3, column=1, sticky='news')
    
        root.mainloop()
    

    main.py

    It imports keyboard and uses keyboard.create(...) to show keyboard and assing it to selected Entry or Text.


    import tkinter as tk
    import keyboard
    
    # --- main ---
    
    if __name__ == '__main__':
        root = tk.Tk()
        root.title('Hello World!')
    
        label = tk.Label(root, text='Form')
        label.grid(row=0, column=0, columnspan=3)
    
        #-----    
    
        label1 = tk.Label(root, text='Entry 1')
        label1.grid(row=1, column=0)
    
        entry1 = tk.Entry(root)
        entry1.grid(row=1, column=1, sticky='news')
    
        button1 = tk.Button(root, text='Keyboard', command=lambda:keyboard.create(root, entry1))
        button1.grid(row=1, column=2, sticky='news')
    
        #-----    
    
        label2 = tk.Label(root, text='Entry 2')
        label2.grid(row=2, column=0)
    
        entry2 = tk.Entry(root)
        entry2.grid(row=2, column=1, sticky='news')
    
        button2 = tk.Button(root, text='Keyboard', command=lambda:keyboard.create(root, entry2))
        button2.grid(row=2, column=2, sticky='news')
    
        #-----    
    
        label3 = tk.Label(root, text='Text 1')
        label3.grid(row=3, column=0)
    
        text1 = tk.Text(root)
        text1.grid(row=3, column=1, sticky='news')
    
        button3 = tk.Button(root, text='Keyboard', command=lambda:keyboard.create(root, text1))
        button3.grid(row=3, column=2, sticky='news')
    
        root.mainloop()
    

    I was thinking to create widget which has Entry + Button Keyboard because you use this combination very often. Maybe I create it later.