I have a QTreeWidget, and I'm using drag&drop with it.
How can I prevent it from dropping in-between 2 items? It's when the cursor becomes a line.
I looked at:
QTreeWidget.supportedDropActions() - but that seems to only switch between copy and move.
QtCore.Qt.ItemIsDropEnabled flag - while I'm using that for a lot of other things, I'm not sure how to implement that to stop being able to drag between 2 items.
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.
I don't have a lot of GUI programming experience and very little in Tkinter, so bear with me. It seems to me that the Tkinter menu interface is seriously wrong. I'm referring in particular to the way menu entries are addressed.
Menu entries are not widgets. add_command - or, for that matter, any add - does not return an object which we can use to address the entry. In order to
reconfigure
delete
insert relative to
an entry, an index must be provided. The index is, usually, just an index in the current list of entries in the menu. That means, all entries that exist (after additions and deletions) at the present time in the index.
It seems logical to organize the code in a GUI around groups of functions that are related from a user's point of view. Say, Undo and Redo should be together in the Edit menu. But the Edit menu may also contain other groups of functions - Cut, Copy, Paste, or perhaps Find. It makes sense to put the code that handles Undo and Redo in one module, the code for Cut, Copy and Paste in another, the code for Find in yet another. These modules are unrelated to each other, except for the fact that they all exist in the Edit menu. However, just because of that fact, it seems that in Tkinter menus they need to know if a module "above" inserts or deletes an entry in its own "area", because that affects the indices of their own entries. Isn't that quite fragile? Or am I missing something?
I have multiple QGraphicsItems with the ItemIsSelectable, ItemIsMovable and ItemSendsGeometryChanges flags.
Sometimes I want to disable selection and movement of those items, and I'm currently doing this by calling QGraphicsItem.setEnabled(False). However, when the cursor is on top of a disabled QGraphicsItem, the scroll wheel doesn't scroll the view anymore. I have tried to find a solution through Google, but I haven't found any working solutions.
So, my question is: Is there an easy way to *not* make disabled items prevent scrolling if the cursor is hovering over them?
If not, I can just write an own function that disables the mentioned flags instead of calling setEnabled() on the QGraphicsItem, but I'm still wondering why scrolling doesn't work, and if I really can't let disabled items ignore the scrolling event.
One thing I've tried already, is disabling Qt.MiddleButton with a setAcceptedMouseButtons() call, but that didn't seem to change anything.
My setup: Windows 7, Python 2.7.3 and PyQt4
void QGraphicsItem::setEnabled(bool enabled)
Disabled items are visible, but they do not receive any events
Mouse events are discarded
That is the explanation why your mouse events - scroll wheel - are not working.
And why trying to change designation of mouse buttons doesn't make a difference - the item simply doesn't care :-)
If you want to disable movement and selection of a QGraphicsItem, the best way is to unset their QGraphicsItem::ItemIsSelectable and QGraphicsItem::ItemIsMovable flags.
This really seems simpler... As you probably already noticed.
The alternative - as the linked answer shows - is to install a scene event filter, have other items filter the disabled items events. The following question has good info:
Event filter on QGraphicsItem
I have a wxPython application with a multi-stage GUI. First a simple form pops for selecting from one of many (> 100) options (it's a part number list with a search box). Once the user has made their selection it builds the appropriate form and shows it, hiding the initial selection dialog. Due to the nature of this project, each secondary form has several matplotlib figures in a Notebook, around 7 or 8 figures each with 2-5 axes each. Because of this, the form takes several seconds between initialization and when it can be shown on the screen.
Does wxPython have a way to build a frame in the background? I don't mind forcing the user to wait a short while before it can be shown, but as it is right now building the form hogs the event loop and everything becomes unresponsive. If I use a thread to build the form, it completes successfully but when I call .Show() nothing happens and there's no error message.
As you can imagine, such a GUI has fairly complex code so it would be difficult to show a SSCCE (and it's not open source). If needed I can try to hack together something that would approximate my problem.
I have used BusyInfo before to tell the user that something is happening. You would put that in your frame's init() BEFORE you actually start creating the matplotlib figures. You can read about it here:
http://wiki.wxpython.org/BusyInfo
Another idea would be to create a second frame with a progressbar in it and a message. The progressbar would be set to just bounce back and forth and when you got done creating the matplot stuff, you would close the second frame.
Mike's idea of using wxBusyInfo is useful when something takes a long time, but it's possible you could make it take less time instead (or at least as well).
First, when inserting many (although I wouldn't say that 100 is that many, 1000 however definitely is) items into a wxChoice, freeze it before adding them -- and thaw it afterwards. This should cut down the time needed for the insertion drastically.
Second, creating all controls of a multi-page wxNotebook (or another wxBookCtrl) can be long, even in C++. So the idea is to not do it immediately but only create the controls of the page you are going to initially show to the user. And then create the other pages controls only when the user is about to select them, i.e. in your wxEVT_BOOKCTRL_PAGE_CHANGING event handler.
If you put this in place, you might not need wxBusyInfo any longer...
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).