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.
Related
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.
In the app I'm trying to automate there is an error window that could pop-up in literally any moment of application work. Then I need to perform some actions like logging this event and stop next automation steps. So I need to catch this moment. How can I do it?
This window always has the same properties (auto_id) so I can describe it before it exist. I can think of using something like a timer which will always check for existence of this window (with the help of .exists(), I guess). But maybe there is a better way of doing it?
I'm talking about <<NotebookTabChanged>> event that ttk.Notebook can be bound to. Say I have:
def tabChanged(self, event):
print "tab changed"
And say I want to manually trigger this method. What I actually mean by this is, say I have a basic, tabbed GUI and there's a start button which makes plots when you click it. There are plots on each tab and when you change tabs, <<NotebookTabChanged>> is triggered, which is an automatically created event by ttk.Notebook. I already have a self.tabChanged method for this case. What I wanna do is, I wanna make my start button trigger this event so I don't have to create a new method just for the button which will do the exact same thing as self.tabChanged. So I need a way of triggering the event through a button click, but remember, that event is ttk.Notebook's own event and apparently it was designed to be used with tabs, not buttons. Is there a way to trigger <<NotebookTabChanged>> manually with a button click?
You can generate virtual events (eg: events that begin and end with << and >>) with event_generate:
self.the_notebook.event_generate("<<NotebookTabChanged>>")
I'm in the process of creating a filling program with Python 3.3/Tkinter and have run into an issue that's really stumping me. Basically, I want to prevent button presses from registering while certain processes are taking place. I tried changing the button's state to state='disabled' but this only delays the click from registering until after the function is finished running. In other words, despite the button being "disabled", if it's clicked, the button press will register as soon as it's re-enabled. Please see the example code below.
def Button_Action:
Button.config(state='disabled')
#Activate some hardware that takes a few seconds.
Button.config(state='normal')
So, the question is: How can one selectively ignore button presses in Tkinter/Python 3?
I'm really new to Python and have tried searching for relevant questions to no avail, so please forgive me if this is a stupid question, or has been asked before. Also, I have tested this with both Radiobuttons as well as, standard Buttons (in case that helps).
You can use update method.
def button_action():
b.config(state='disabled')
b.update() # <----------
# Activate some hardware that takes a few seconds.
b.update() # <----------
b.config(state='normal')
The first call to update is to make the button displayed as disabled state.
The second call to update is to handle all pending event (clicks in your case) before enable the button.
BTW, it's normal state, not enabled that make the button back to normal state.
I am using a SearchCtrl with a dropdown menu and I'm having some trouble with the events. When I click the little arrow next to the search button, the EVT_SEARCHCTRL_SEARCH_BTN is triggered, which is not what I want. I only want the EVT_MENU_RANGE to be triggered after I clicked an item, and not also the EVT_SEARCHCTRL_SEARCH_BTN before i click it.
self.search_ctrl = wx.SearchCtrl(self.panel_1, -1,
style=wx.TE_PROCESS_ENTER)
self.search_menu = wx.Menu()
self.search_items = {"text1":"value1", "text2":"value2"}
for txt in self.search_items:
self.search_menu.Append(-1, txt)
self.search_ctrl.SetMenu(self.search_menu)
self.Bind(wx.EVT_SEARCHCTRL_SEARCH_BTN, self.search, self.search_ctrl)
self.Bind(wx.EVT_MENU_RANGE, self.onSearchMenu)
Although I should probably add id's to the menu bind, this isn't causing the problem. The code works as expected when I comment out the search button bind.
UPDATE
Apparently this isn't a problem, but a 'feature' of the searchctrl. I tried the wxpython demo and the menu also showed up if I just clicked the search button, and not the arrow. It is apparently one button, instead of the two i thought it was.
Is there a way to accomplish my original request? Do i have to manually modify a textctrl, or is there an other solution?
All the examples I've seen suggest you need to specify a range of IDs when you call your menu bind.
Maybe by default it binds to something unexpected... ?
Edit - In light of your update, it seems likely that you're going to need to make a custom control to me..