Search code examples
python-3.xtkinterchatbotkeyboard-eventsguizero

How to deal with none letter keyboard input errors in python guizero/tkinter?


When I press tab it selects all of the text in the input box unless I set the input box multiline to true but it ends up giving the first post a strange format. I would like tab key to act like it normally does in any other program. I am also getting errors when I press Shift or Caps lock in the shell based on whatever the first key input "if" statement is. Both Shift and Caps lock still end up making the text display properly.

I have tried adding an if statement to avoid tab key errors but it doesn't seem to work. I tried using pass and just a normal print statement.

What I'm using.

Error I'm getting

if ord(e.key) == 9: #tab key TypeError: ord() expected a character, but string of length 0 found

from guizero import *

app = App(bg='#121212',title='Virtual assistant',width=500,height=500)
box=Box(app,width='fill',height=420)
box.bg='light gray'
Spacer_box=Box(box,width='fill',height=5,align='top')
userName='Test Username: '

#A is set as the default text value to test if posting into the box works
#Setting multiline to true changes the first post format but allows for the tab key to work properly 
input_box = TextBox(app,text='A',width='fill',multiline=False,align="left")
input_box.text_size=15
input_box.bg='darkgray'
input_box.text_color='black'
input_box.tk.config(highlightthickness=5,highlightcolor="black")


def key_pressed(e):
    
    #stop tab key from highlighting text only when input_box multiline is set to true
    #in the input_box above
    if ord(e.key) == 9: #Tab key
        print('Tab pressed')
        
    elif ord(e.key) == 13:#Enter key
        #Checks if input box is blank or only white space. 
        if input_box.value.isspace() or len(input_box.value)==0:
            print('Empty')
            input_box.clear()
        
        else:#User's output.
            Textbox=Box(box,width='fill', align='top')
            Usernamers=Text(Textbox, text=userName,align='left')
            Usernamers.tk.config(font=("Impact", 14))
            User_Outputted_Text = Text(Textbox, text=input_box.value,size=15,align='left')
            print('Contains text')
            input_box.clear()
            #Test responce to user
            if User_Outputted_Text.value.lower()=='hi':
                Reply_box=Box(box,width='fill',align='top')
                Digital_AssistantName=Text(Reply_box,text='AI\'s name:',align='left')
                Digital_AssistantName.tk.config(font=("Impact", 14))
                Reply_text = Text(Reply_box,text='Hello, whats up?',size=15,align='left')

            

input_box.when_key_pressed = key_pressed        

app.display()

Solution

  • Adding this at the beginning of key_pressed function will eliminate the error when Caps Lock/Shift or any key that returns an empty string is pressed.

    if e.key=='':
        return
    

    The following has worked in preventing the Tab key from selecting the text

    if ord(e.key) == 9: #Tab key
        print('Tab pressed')
        input_box.append(' '*4)
        input_box.disable()
        input_box.after(1,input_box.enable)
    

    Basically I have disabled the widget followed by enabling it after 1 millisecond.

    UPDATE

    Another approach could be to bind the Tab key to the Entry widget used internally (which can be accessed by using the tk property as stated in the docs). I would recommend this approach over the previous, also, because the append method adds the text at the end, there is no built in method to insert the text at the current location, so you would ultimately end up using the insert method of tkinter.Entry with the index as 'insert'.

    def select_none(event):
        input_box.tk.insert('insert',' '*4)
        return 'break'
    
    input_box.tk.bind('<Tab>',select_none)
    

    Using return 'break' at the end of the function prevents other event handlers from being executed.