I am trying to make a keylogger using Tkinter, but the binds are not working at all. I think the bind isn't calling the subprogram, but it provides no error so that is just an educated guess.
I started this project 3 days ago and expected it to be done yesterday. But this issue kept on cropping up, I am using python 3.6.1.
Here is what I have already tried
Using lambda
Putting "command =" before the function
Changing "def keypress():" to "def keypress(event)"
Making the bind in a frame
Binding each individual button the keyboard
I have even copied someone's keylogger code and came across the same issue (yes it was python-3.x)
It is made even more frustrating by the number of answers on forums that don't work and the days of googling and looking at the documentation.
import tkinter
from tkinter import *
window = Tk()
window.title("Test")
window.config(bg = "white")
frame = Frame(window, width = 1000, height = 1000)
frame.place(x = 0, y = 0)
def keypress(event):
print("pressed", repr(event.char)) #changed repr to str and also tried deleting it
frame.bind("<Key>", lambda: keypress(event)) #other variations of this line include frame.bind("<key>", keypress), frame.bind("<key>", keypress()), frame.bind("<key>", keypress(event))
The expected input is just
>>> Pressed [the key that I pressed]
but the output that you actually get is...
>>>
Nothing.
Any and all help would be wonderful, thanks in advance!
You don't need lambda if you aren't passing any arguments.
frame.bind("<Key>", keypress)
Also, keybindings only work if the widget has the keyboard focus. By default a frame does not get the keyboard focus. If you want to bind to a frame, you must force it to have keyboard focus:
frame.focus_set()
Related
I am looking for a simple way to display changing real time data in a GUI in python. I am connected to 2 devices and want to display data constantly (like 20 different values), and when I press a button I want to control the one device.
Unfortunately I fail already with the display of the data. For this I have looked at some tkinter tutorials and explanations.
My idea was to implement it with a config function and to overwrite the label continuously. As example how I wanted to display one value:
import tkinter as tk
from pydualsense import pydualsense
# connect to the device
dualsense = pydualsense()
dualsense.init()
# create a window
window = tk.Tk()
# function for updating data
def show_data():
global dualsense
data_label_output.config(text=dualsense.state.LX)
# showing the data as a lable
data_label_output = tk.Label(window)
data_label_output.grid(row=1, column=1)
show_data()
#### or different solution
# showing the data as a lable
data_label_output = tk.Label(window, comand=show_data)
data_label_output.grid(row=1, column=1)
window.mainloop()
Unfortunately, the value is displayed only once at the beginning and nothing changes after that.
Another problem:
When I press the button, I want to be able to control the one device. For this I have a while True loop that permanently checks if a button is pressed and then executes actions. As a separate program no problem, but how do I integrate this into the tkinter GUI? When I start this PyCharm always crashes.
I use PyCharm and Python 3.8
About simple and functional ideas I would be happy, also to other tools/modules etc., as long as you can easily and quickly implement the idea. It's only for a research project and the programming is only a means to an end.
You can use the after method in tkinter to run something after a short delay. The following code will run show_data once the GUI is ready and then again every 1000 milliseconds.
import tkinter as tk
from pydualsense import pydualsense
# connect to the device
dualsense = pydualsense()
dualsense.init()
# create a window
window = tk.Tk()
# function for updating data
def show_data():
global dualsense
data_label_output.config(text=dualsense.state.LX)
window.after(1000,show_data)
# showing the data as a lable
data_label_output = tk.Label(window)
data_label_output.grid(row=1, column=1)
window.after_idle(show_data)
window.mainloop()
This resolves the updating issue, I'm not sure what behaviour you want when you press the button but if you elaborate and explain, I might be able to help and update this answer.
This question already has an answer here:
When should I use root.update() in tkInter for python
(1 answer)
Closed 1 year ago.
Beginner programmer here currently trying to learn Tkinter for a school assignment.
I have a GUI class that stores the Tkinter labels etc, the labels are innitiated like this:
# GUI for Player 1
self.player_1_name_field = Label(
self.root,
text="Player 1",
font=GUI_Settings.player_information_font,
anchor=W,
background=GUI_Settings.playerfield_active_color
)
I then create a Game() object that looks like this:
class Game():
def __init__(self):
self.GUI = GUI()
self.GUI.initializeBoard()
self.GUI.root.mainloop()
When I run the code, the labels do get created and are where they are supposed to be, but are completely black. Once I move or resize the window it instantly becomes how I want it to be, it just behaves weird when at the start of the code
The interesting thing is that I also have a Canvas and a List that work perfectly fine, only the Labels are not cooperative
If you need further info, just ask for it!
Thank you!
Edit 1: I have a function called drawWindow() that redraws the chessboard when I re-configure the window. In the init of the GUI class I set self.root.bind("<Configure>", self.drawWindow). If I remove that line of code, the Labels work but the Canvas doesn't anymore. I'm so confused. For anyone wanting to take a look at my tiny code: https://codeshare.io/DZYzyZ
See comment of Thingamabobs
The issue is self.root.update(). Remove this line and you'll be fine.
When should I use root.update() in tkInter for python.
This works but you shouldn't do it
This is a tricky issue. Your problem come from the bind of the configure event. Bind to the root window, it is applied to all sub-widgets of the window, which cause the bug (I don't know why yet).
This will solve your issue (line 202):
self.chessboard.bind("<Configure>", self.drawWindow)
instead of:
self.root.bind("<Configure>", self.drawWindow)
Result without moving or resizing the window:
I found the information here (french forum).
I'm writing my first GUI program today using Tkinter and I have stumbled onto a problem. I am trying to make a game that starts with an introduction window that closes after you press a button, then opens a new window where you can choose one of two modes. Unfortunately, I just can't get it running. It looks a little something like this.
#These are the functions that I defined to make it work
def start():
root.destroy()
def Rules_mode_1():
root.destroy
rules1 = Tk()
understood1 = Button(rules1, text="I understood", command="Start_game_mode_1")
understood.pack()
rules1.mainloop
# I haven't added rules 2 yet cause I couldn't get it to work with rules 1 so I haven't even #bothered but it would be the same code just switching the 1 for a 2. But really it isn't even
#necessary to have 2 different rule functions because the rules are the same but I couldn't think
#of another way to go about it. if you have an idea let me know
def Start_game_mode_1():
rules1.destroy #<----- THIS IS WHERE THE PROBLEM LIES. JUST DOESN'T RUN
gamemode1 = Tk()
#Here I would have the game
gamemode1.mainloop()
#now same here don't have gamemode 2 yet cause it just doesn't work yet
#This is where it really starts
root = Tk()
startbutton = Button(root, text="Start", command=start)
startbutton.pack
root.mainloop
root = Tk()
def mode():
mode1 = Button(root, command=Rules_mode_1)
mode1.pack
mode2 = #Buttonblablabla
mode()
root.mainloop()
Now I've been trying around for hours, trying to give the mainloops different names. For example giving the
rules1.mainloop
#the name
root.mainloop
but that obviously didn't work. I tried it with dozens of helper function and with the lambda expression and did hours of research but just can't seem to fix it. Does anybody have any ideas? Please be respectful and keep in mind it's my first time using Tkinter.
Thank you for your help!
After the comments didn't really help me I just tried things out for hours and in case anybody ever is having a a similar problem and reads this: The rules1 variable is inside a function, and therefore only local, which means it can't be destroyed in another function. I fixed it by making it a global, like:
def Rules_mode_1():
root.destroy
global rules1
rules1 = Tk()
understood1 = Button(rules1, text="I understood", command="Start_game_mode_1")
understood.pack()
rules1.mainloop
After that I could destroy the mainloop in the next function.
I am trying to get keypresses in Python (2.7.10), bit I had no luck with getch(), as ord(getch()) was returning 255 constantly, so I am now using Tkinter. (I believe that Tkinter is also cross-platform so that should help as i plan to run this script on a Linux device).
I need to be able to get keypresses, even if they are not pressed while the Tkinter window is not active.
Here is my code:
from Tkinter import *
import time, threading
x = "Hi!"
def callback(event):
x = "key: " + event.char
print(x)
def doTk():
root = Tk()
root.bind_all("<Key>", callback)
root.withdraw()
root.mainloop()
thread1 = threading.Thread(target=doTk)
thread1.deamon = True
thread1.start()
I am not reveiving any errors, it is not not registering keypresses. I have also tried this without using threading, but it still does not work.
Please also note that I cannot use raw_input() as I need this to be able to run in the background and still get keypresses.
I am aware that this does not produce a frame, I do not want it to.
Thanks in advance for any help :)
PS: I have looked to other answers on StackOverflow and other sites, but they all either don't work or give solutions where keypresses are only registered when the tkinter frame is active.
I can make a basic python application like so:
from tkinter import *
block = None
def moveUp(event):
field.move(block,0,-50)
root = Tk()
field = Canvas(root, width = 300, height = 300, bg = 'light blue')
field.pack()
block = field.create_rectangle(100,100,110,110)
field.bind('<Button-1>',moveUp)
mainloop()
and it will behave just like you would expect. It creates a square on a Canvas and moves that square up 50 pixels every time you click in the Canvas.
However, When I replace
field.bind('<Button-1>',moveUp)
to, for example,
field.bind('<Return>',moveUp)
the square does not move, no matter how many times I press the Enter key. This problem persists for any kind of keyboard input (e.g <space>, etc), but any input involving the mouse is fine.
Any input at all is appreciated. Thanks!
The field does not have focus, and therefore does not capture the keypress. One option is simply to make the binding more general:
field.bind('<Return>',moveUp)
to
root.bind('<Return>',moveUp)
Another option is to set the focus to the field:
field.bind('<Return>',moveUp)
field.focus_set()
Not entirely sure what's the reason, but it seems to work if you use bind_all instead of bind.
field.bind_all('<Return>',moveUp)
My guess is that using the keyboard, the canvas does not have focus and so does no register the event. Using bind_all, the event is registered when any widget of the application has focus.
See here for some information on levels of binding.