Python Tkinter Command Click - python

I need to bind command button-click to a function in python. I have already bound the flag function to right click, but this only work when right-clicking with a mouse. As I write the majority of my code on a laptop, this is horribly inconvenient. Here is what I currently have:
# set up the mouse click listeners
self.bind('<Button-1>',self.expose)
self.bind('<Button-2>',self.flag)
#this is where I want to bind self.flag to command click
I'd like to use self.bind if possible, and simply bind command click to self.flag. Is it possible to do this?

You can just use:
self.bind("<Command-Button-1>",self.flag)
This can be done in addition to <Button-2> and you may want to also bind <Control-Button-1> for compatibility.
I would normally link to http://infohost.nmt.edu/tcc/help/pubs/tkinter/event-modifiers.html but it seems to be down at the moment, basically there are a few modifiers that can be used in combination with Button or Key:
Alt True when the user is holding the alt key down.
Any This modifier generalizes an event type. For example, the event pattern '<Any-KeyPress>' applies to the pressing of any key.
Control True when the user is holding the control key down.
Double Specifies two events happening close together in time. For example, <Double-Button-1> describes two presses of button 1 in rapid succession.
Lock True when the user has pressed shift lock.
Shift True when the user is holding down the shift key.
Triple Like Double, but specifies three events in rapid succession.
So you could for example bind <Control-Shift-Double-Button-1> if your program needed to be that elaborate.

Related

Does Python evdev library have an event specific grab or passthrough?

A python evdev device has a .grab() function that prevents other processes from getting input events on the device. Is there any way to limit this to specific events from a device?
For my example, if I .grab() a pen input device that has pressure sensitivity and tilt and 2 click buttons on the side, how would I 'grab' ONLY the 2 click buttons but let the rest of the input (the tip, pressure sensitivity and tilt) be caught by the rest of the system as normal?
One of my pen buttons is normally a right click mouse event. I want to make it do something else but it still pops up the right click menu so I'm trying to figure out how to stop that.
I tried doing the grab and ungrab when the event occurs. Like event > grab > do my stuff > ungrab. But that is obviously too late and the OS still pops up the menu.
I tried doing the full grab, then in the event loop if it is a button press do my stuff, otherwise create a UInput event injection by just passing the event back to the system. This was a bit of a tangled mess. Permissions are required. When I finally got past that, the movement was offset and the pressure/tilt wasn't working... I think it is something to do with the DigiMend driver that actually makes that stuff work and/or xinput settings I have to pass to calibrate the tablet. But I'm not interested in writing all the pressure/tilt functionality from scratch or anything like that, so I need the DigiMend stuff to work as normal. So I gave up on this idea for now.
The only other thought I had was figure out why the OS defaults to the behavior it does and see if I can just manually disable the actions (i.e. Why does it think that button is a right mouse click and make it think that button is nothing instead.)
So I guess this is a 3 level question.
Can I achieve the the grab functionality on select events instead of the device as a whole?
If the passthrough idea was better, is there a way to achieve this without having to do any permission modifications and be able to pass the exact event (i.e. no offset and such that I experienced?)
If evdev does not have this ability or it'd be easier to do in another way, like disabling the defaults for the pen in the OS somehow, I am open to suggestions. I am using Kubuntu 20.04 if that helps.
Any help would be appreciated, let me know if more info is needed, thanks in advance!
I ended up going with #3 and using xinput. Figured I'd put up this answer for now in case others come across this and want to do something similar.
The workaround was actually kind of simple. I just use xinput to remap the 2 buttons. So evdev doesn't have to grab at all. Just disable those buttons and everything goes normally except those, which I listen for with evdev.
xinput set-button-map {} 1 0 0 4 5 6 7
My device has 7 buttons and are normally mapped 1-7. Which are all mouse equivalents of left click, middle click, right click, etc...
By using that string and passing the device ID in for the {} I just run that with subprocess first. And voila, no more right click menu. And I can use evdev to map the events to whatever I want.

PySimpleGui: how to remove event-delay in Listboxes?

When reading events from a simple button in PySimpleGui, spamming this button with mouseclicks will generate an event for each of the clicks.
When you try to do the same with Listboxes (by setting enable_events to True for this element) it seems like there is a timeout after each generated event. If you click once every second, it will generate all the events. But if you spam-click it like before it will only generate the first event.
I'm not sure if this behavior is intended (only started learning PySimpleGui today), but is there a way to get rid of this delay? I tried checking the docs but can't find it mentioned anywhere.
I think the reason is that a Listbox reacts to click events, but also to double click events. A Button does not. This behavior looks like consistent.

Key Event Handling using Tkinter in Python

check the following link out :
[PyObjC Key Event Handling Question] Key Events Handling using PyObjC in Mac OS X
This was my initial question. I somehow managed to find a built-in plugin to solve the Key Event Management, but using Python. It is called Tkinter.
from Tkinter import *
root = Tk()
def screenshot(*ignore): os.system("screencapture -s %s" % check_snapshot)
root.bind('<Return>', greet)
root.mainloop( )
On pressing return (enter) key, it would successfully call screenshot function, and it would work.
Now, what I am looking for is, whenever I press combination of keys, like Command+Shift+4, the above function should be call.
This should be done in the same manner for Command+Shift+3 and Command+Shift+5 as well.
This should be done by checking which combination of keys are pressed, and accordingly, their respective screenshot functions should be called.
Also, this app shortcuts shouldn't be just relied on this app's window or frame, the window / frame of this window shouldn't be visible, yet, the shortcuts should work and trigger their respective functions.
root.withdraw()
This is the built-in function which hides the Tkinter window, but then, I am unable to invoke any of the functions. These functions only work on Tkinter window, or else, keys shortcuts don't work.
Any help would be appreciated.
Tkinter events only work when the tkinter window has focus,and for it to have focus it must be visible. You cannot use tkinter to handle events while another program is in the foreground.
The format of an event is <modifier-modifier-event-detail>, with modifier and event being optional. Event is something like KeyPress, ButtonPress, ButtonRelease and so on. Detail gives more detail, such as which key, or which button. For example, <ButtonRelease-1> is for releasing mouse button 1 (one).
Modifier is where you specify control, alt, delete or shift, and you can have more than one. Shift is a bit special, because it is often interpreted by the OS before tkinter ever sees is. So, for example, "Shift-3" on an American English keyboard is "#". Thus, instead of <Shift-3> you would use <#>.
Putting that all together, command-shift-3 would be <Command-#>. However, if you do that on a Mac, it will intercept that event and do a screenshot, so the binding will only work on Windows and Linux. On each OS there are a few key bindings you cannot override.
The best description of the format to use for specifying events is the tcl/tk man page on bind. Even though you're asking about tkinter, the underlying engine is tcl/tk.

Wait for button click

I'm trying to create a GUI that will have some preset test to run. Depending on what the user's selection is a secession of test will run. I'm trying to figure out what is the best way to run a test in a thread and then wait until the user presses the next button to continue.
The current way the program knows what test to run is by create a dictionary like so
A = {0:[0,0,0],1:[1,0,1],2:[0,1,1]}
the key would represent the index of a combo box and the list represent whether the test runs or not, so 0 mean don't run that particular test and 1 mean do. So, I would have a for loop that would run through the list and if it's 0 it goes to the next list element, and if it's 1 it configures the test runs it and then I would like it to wait until the user presses the next button in the GUI.
EDIT: Instead I implemented a state machine method, using Qtimer. So the GUI will stay in the wait state until the GUI send sends a signal to move from the wait sate to the next state after a button has been pressed
You can do it simple like this: first, disable next button in your GUI using yourNextButton.setDisabled(1); second, enable it at the end of your test yourNextButton.setDisabled(0) (I assume it is one method); with the button enabled,which means your test is done, you can click it and connect it with next operation you need to be done (next test or whatever), but do not forget to disable it again when it's clicked.
If you need different behavior feel free to ask.

Multiple key press detection wxPython

I am creating a Project Manager using wxPython it has a splitter window. On one side is a tree that shows the names of and opens the files and on the other size is a textctrl that is used to edit the file.
One problem I am having is that I would like it to go back 4 spaces when SHIFT and TAB are pressed, I have code working that add's 4 spaces when TAB is pressed.
I am also have a problem that when I add a file that is in a different folder to my programs cwd the tree adds a new node and the file appears under this node and I am struggling to get the tree to save to a file.
Also I would like to know how to add an icon to an item in the tree from an external png file.
I would appreciate any help that could be given with either of these problems.
To catch multiple keys, you either need to catch EVT_CHAR or use an accelerator table. The latter is easier while the former may give you more control. Here are a couple tutorials for you:
wxPython: Catching Key and Char Events
wxPython: Keyboard Shortcuts (Accelerators)
I don't know use WxPython and so don't have much idea about it. But in general what you can do is whenever a key is pressed, call a callback function and you could get the time when the key was pressed. save it somewhere. And when the next key is pressed, get the time. compare both times, if there's not much significant delay (you can decide the delay), it means that both the keys were pressed simultaneously (although they were not).

Categories

Resources