from tkinter import *
def quit_1(event):
print("you pressed Win_L")
root.quit()
def quit_2(event):
print("you pressed Win_L+D")
root.quit()
root = Tk()
root.bind('<Win_L>', quit_1) #working
root.bind('<Win_L-D>', quit_2) #not working
root.mainloop()
How I bind Win_L + D event to a funcction
commenting line
root.bind('Win_L-D',quit_2) runs the program
To bind the Win_L + D key combination to the quit_2 function, you need to modify the event string in the bind method. Instead of using '<Win_L-D>', you need to use '<Win_L>d':
root.bind('<Win_L>', quit_1)
root.bind('<Win_L>d', quit_2)
This is because Win_L is a modifier key and cannot be used in combination with other keys. When you press Win_L + D, the Windows operating system generates a new key code for the combination. In Tkinter, this code is represented by d (the d key), so you need to use it in the event string.
With this change, pressing the Win_L + D key combination will print "you pressed Win_L+D" to the console and quit the root window.
Related
this works for normal keys like [q,w,e,r,1,2,3] but i cant make it work with keys like with Shift,Enter,Backspace etc,any idea how to make it work?
from tkinter import *
root=Tk()
root.geometry("200x200")
def func1(event):
print(f'{event.char} key was pressed')
def func2(event):
print(f'{event.char} key was released')
root.bind("<KeyPress>",func1)
root.bind("<KeyPress>",func2)
root.mainloop()
From the docs:
.char:
If the event was related to a KeyPress or KeyRelease for a key that produces a regular ASCII character, this string will be set to that character. (For special keys like delete, see the .keysym attribute, below.)
Since here you are trying to get a special key like Shift, Caps and so on, you can use keysym which will provide the key name.
Based on your comments, I see that you were expecting for a function that will trigger when the Shift key was pressed and released. This can be achieved by using KeyPress and KeyRelease before the key name:
def func1(event):
print(f'{event.keysym} key was pressed')
def func2(event):
print(f'{event.keysym} key was released')
root.bind("<KeyPress-Shift_L>",func1)
root.bind("<KeyRelease-Shift_L>",func2)
Some useful reference links:
54.6. Writing your handler: The Event class
54.5. Key names
you have to use these to .bind function :
root.bind("<Alt-s>",fAlt) # Alt+s pressed
root.bind("<Control-c>",func) # C character + Ctrl
root.bind("<Alt>",func1) # The Alt key is held
root.bind("<Control>",func2) # The Ctrl key is held
root.bind("<Shift>",func3) # The Shift key is held
root.bind("<KeyPress>",func4)
root.bind('<Left>', leftKey)
root.bind('<Right>', rightKey)
root.bind('<Up>', upKey)
root.bind('<Down>', downKey)
I would like to do this for the Enter key but not the Return key:
root.bind('<Return>',func)
If you are not clear on the difference between the enter key and the return key
http://en.wikipedia.org/wiki/Enter_key
I would appreciate help, thank you!
One way to find out what's the correct key binding is to create a key binding for all keys and printing the keysym of the event. Now, just hit the key you want to bind the event to and see what it prints.
import Tkinter
root = Tkinter.Tk()
def func(event):
print event.keysym
root.bind("<Key>", func)
root.mainloop()
When pressing the Enter key, this will print KP_Enter, so your binding should be
root.bind('<KP_Enter>', func)
I've been working on a Tkinter (Python) project that displays a list of strings using the Text widget recently, but I ran into an issue I couldn't manage to solve :
On startup, I want the first line to be highlighted, and when I click on up/down arrows, the highlight goes up/down, as a selection bar.
I succeed to do that, but the problem is that the highlight only appears when arrows are pressed, and when they are released, it disappear. I'd like it to stay even when I'm not pressing any key.
Here is my code :
class Ui:
def __init__(self):
# the list I want to display in Text
self.repos = repos
# here is the entry keys are bind to
self.entry = Entry(root)
self.entry.pack()
self.bind('<Up>', lambda i: self.changeIndex(-1))
self.bind('<Down>', lambda i: self.changeIndex(1))
# here is the Text widget
self.lists = Text(root, state=NORMAL)
self.lists.pack()
# inits Text value
for i in self.repos:
self.lists.insert('insert', i + '\n')
self.lists['state'] = DISABLED
# variable I use to navigate with highlight
self.index = 0
self.lists.tag_add('curr', str(self.index) + '.0', str(self.index + 1) + '.0') # added + '.0' to make it look '0.0' instead of '0'
self.lists.tag_config('curr', background='#70fffa', background='#000000')
self.root.mainloop()
def changeIndex(self, n):
# error gestion (if < 0 or > len(repos), return)
self.lists.tag_delete('curr')
self.lists.tag_add('curr', str(self.index) + '.0', str(self.index + 1) + '.0')
self.index = self.index + n
# to make it scroll if cannot see :
self.lists.see(str(self.index) + '.0')
I haven't seen any similar problem on Stack, so I asked, but do not hesitate to tell me if it is a duplicate.
Do you guys could help me please ? Thanks !
EDIT: Here is the full code if you want to give it a try : https://github.com/EvanKoe/stack_tkinter.git
EDIT : I added the main.py file (the """backend""" file that calls ui.py) to the demo repository. This way, you'll be able to run the project (be careful, there are "YOUR TOKEN" and "YOUR ORGANIZATION" strings in main.py you'll have to modify with your own token/organization. I couldn't push mine or Github would've asked me to delete my token)
The following code should do what you expect. Explanation below code
from tkinter import *
repos = ["one","two","three","four"]
class Ui:
def __init__(self, parent):
# the list I want to display in Text
self.repos = repos
# here is the entry keys are bind to
self.entry = Entry(parent)
self.entry.pack()
self.entry.bind('<Up>', lambda i: self.changeIndex(-1))
self.entry.bind('<Down>', lambda i: self.changeIndex(1))
# here is the Text widget
self.lists = Text(parent, state=NORMAL)
self.lists.pack()
# inits Text value
for i in self.repos:
self.lists.insert('insert', i + '\n')
self.lists['state'] = DISABLED
# variable I use to navigate with highlight
self.index = 1
self.lists.tag_add('curr', str(self.index) + '.0', str(self.index + 1) + '.0') # added + '.0' to make it look '0.0' instead of '0'
self.lists.tag_config('curr', background='#70fffa', foreground='#000000')
def changeIndex(self, n):
print(f"Moving {n} to {self.index}")
self.index = self.index + n
self.index = min(max(self.index,0),len(self.repos))
self.lists.tag_delete('curr')
self.lists.tag_config('curr', background='#70fffa', foreground='#000000')
self.lists.tag_add('curr', str(self.index) + '.0', str(self.index + 1) + '.0')
# to make it scroll if cannot see :
self.lists.see(str(self.index) + '.0')
root = Tk()
ui = Ui(root)
root.mainloop()
Few changes made to your code
Changed the Ui function to accept the parent tk object as a parameter
Changed self.index to be initialised to 1 rather than 0 since the first line on a text box is 1 not 0
Bound the Up/Down keys to the entry box. Not sure why this is what you are going for but this seems to be what your comments indicate
Added some checking code to limit the index value between 1 and len(repos)
Re-created the tag style each time it is set since you delete the tag (this is why it wasn't showing)
I'd suggest that you look to bind the up/down button press to the text box rather than the entry box. Seems a bit strange to have to select a blank entry box to scroll up and down in a list.
Also, why aren't you just using the build in Tkinter list widget?
I finally managed to solve the problem, and it was due to my event bindings. I made the decision (to improve the UX) to bind up/down arrows on the top Entry instead of binding em on the Text widget. I bind 4 events :
Up arrow => move highlight up,
Down arrow => move highlight down,
Return key => calls get_name(), a function that returns the selected option,
Any other Key => calls repo_filter(), a function that updates the displayed options in the Text widget, according to what has been typed in the Entry.
The problem was that pressing the up/down arrow was triggering "up/down key" event AND "any other key" event, so the highlight was removed since the Text value was refreshed.
To solve this problem, I just had to verify that the pressed key was neither up nor down arrow in the "any other key" event callback :
def repo_filter(evt):
if evt.keysym == 'Up' or evt.keysym == 'Down': # verify that pressed key
return # isn't '<Down>' or '<Up>'
# filter Text widget
Also, I am sorry I didn't give you all the code at the beginning, because, indeed you couldn't guess about those event bindings.
Thanks to everyone who tried to help me !
Im using tkinter and pynput. I have a button to select a trigger key after the user press the key I want to show the ord of the pressed key in a label this is the error: ord() expected string of length 1, but KeyCode found
and here is the code:
TriggerKey = Button(win, text = "Set a trigger key", command = Key_listener)
TriggerKey.place(x = 70, y = 70,)
This is the Listen function:
def Key_listener():
with Listener (on_press=trigger_Key, on_release=release) as trigger:
trigger.join()
and here is where I think the problem is:
def trigger_Key(Key):
TriggerKey = Key
print(TriggerKey) #prints the pressed button for a test
ord_key = ord(TriggerKey)
trigger_key_label.config(text= ord_key)
If you used it with tkinter,it will block your code.
Change your function Key_listener:
def Key_listener():
trigger = Listener (on_press=trigger_Key, on_release=release)
trigger.start()
About your error:
in the trigger_Key,key is a Keycode function.You need to use ord(Key.char).
I have two buttons on my interface. I want both of them to be able to call their respective functions when I either click on them or a hit the Enter Key.
The problem I'm having is that only the last button in the traveral focus gets activated when I hit the Enter Key, even if the preceeding one has the focus. What can I do to resolve this problem.
Useful answer are welcome and appreciated.
This is the problem in question:
from tkinter import *
w = Tk()
def startProgram(event = None):
print('Program Starting')
def readyContent(event = None):
print('Content being prepared')
# Buttons
Button(text='Prepare', command=readyContent).grid(row=10,column=2)
w.bind('<Return>',readyContent) # Binds the Return key to a Function
Button(text='Start', command=startProgram).grid(row=10,column=3)
w.bind('<Return>',startProgram) # Binds the Return key to a Function
w.mainloop()
When you click on the Prepare or Start button, in return you get either Content being prepared or Program Starting repectively. Nothing like that happens when you use the Tab Key to give focus to one button or the other. Even if the focus is on the Prepare button, when you hit Enter you get: Program Starting
This is the solution to my problem.
I hope it helps anyone else having the same problem as me.
from tkinter import *
w = Tk()
def startProgram(event = None):
print('Program Starting')
def readyContent(event = None):
print('Content being prepared')
# Buttons
btn1 = Button(text='Prepare', command=readyContent)
btn1.grid(row=10,column=2)
btn1.bind('<Return>',readyContent) # Binds the Return key to a Function
btn2 = Button(text='Start', command=startProgram)
btn2.grid(row=10,column=3)
btn2.bind('<Return>',startProgram) # Binds the Return key to a Function
w.mainloop()
Have a good day! :)