QAction as keyboard shortcut on QGraphicsItem - qt

I would like to implement keyboard shortcuts for my QGraphicsScene. My graphical objects are derived from QGraphicItem and QObject, so I can use signal/slot connections.
I'm already using QActions for context menus and now I would like to use some of QActions also as actions for keyboard shortcuts on the selected item.
My QGraphicsItems have enabled ItemIsFocusable and ItemIsSelectable via setFlag();
I can receive keyPressEvent(QKeyEvent* event) but in such case I would have to manually test event->key() == Qt::Key_xxx
Is there any way how to do this automatically?
I tried to compare QKeyEvent with QKeySequence, but this doesn't work (because sequence can contain multiple keys).
Thanks for any help

I'm not entirely sure what you mean by automatically. I'm assuming you're just trying to avoid having to manually check the key, which unfortunately I'm not sure of any simpler method.
Catching the QKeyEvent* event like you're doing is generally the way to go, and yes unfortunately once you have the event you'll need to make sure it's expected. You may be able to make the code less ugly by using a bitmask or similar logic operations, but in general I've used a switch on event->key() and that tends to keep things readable.

Related

Catching Qt modifier key releases

I'm a newcomer to Qt, but I'm trying to implement what basically amounts to a video-game-esque input loop in a Qt application (crazy, I know, but see if you can help). I need accurate, one-to-one event handling for key presses and key releases, for all keys, including modifiers, no matter how weirdly you chord-up the keyboard.
Of course, your main access to key events is through QKeyEvent. But let's say the following happens:
user presses and holds Ctrl
user presses and holds Up
user releases Ctrl and Up simultaneously
As far as I can tell, what I get from Qt is:
QKeyEvent for the pressing of Ctrl, by itself (Qt::Key_Ctrl)
QKeyEvent for the pressing of Up, by itself (Qt::Key_Up)
QKeyEvent for the releasing of Ctrl+Up, with key() == Qt::Key_Up and the Ctrl bit reflected in a modifier change.
This may be not exactly accurate, but it's my best guess as to what's going on from way too much debugging of the issue. In any event, the key release events when modifiers are involved are incredibly unreliable.
The Ctrl+Up sequence there at the end is the problem. Now, I know I'm getting modifier state in e->modifiers(), and I'm getting the key press in e->key(). I could do some complicated hacks, trying to remember the modifier state internally, to detect when the user's released the modifier. But then, the Qt docs inform me, speaking of e->modifiers(), that:
This function cannot always be trusted. The user can confuse it by pressing both Shift keys simultaneously and releasing one of them, for example.
This is exactly the case I'm trying to avoid.
Is there any reliable way to keep track of one-to-one key presses and releases, for both normal and modifier keys, in Qt? If not, what's the closest you can get?
EDIT: I can refine this a little bit. It seems that if you hold down Cmd on a Mac, press a few keys (letter keys, say), release them, then release Cmd, you don't get release events for the letter key releases. I'm going to try to isolate a small example and see if this is actually a Qt bug.
I think if you are getting very specific with the keyboard, you are going to have leave Qt and get something that is OS specific, or you need to handle the Qt events before any filtering happens.
Handle Qt Events Before Filtering
Accelerators in Qt look for and wait on Alt+__ combos and you can set up Ctrl+__ combos to be listened to by QAction.
Both of these types of Objects built into QApplication and the general GUI environment, might be interrupting the messages you are getting, and giving you less than what you are expecting.
Qt Documentation: The Event System ... this part has a link to this...
QCoreApplication::notify() ... which tells the highest level that a Qt Application can be written to handle input using the Qt API:
Installing an event filter on QCoreApplication::instance(). Such an event filter is able to process all events for all widgets, so it's just as powerful as reimplementing notify(); furthermore, it's possible to have more than one application-global event filter. Global event filters even see mouse events for disabled widgets. Note that application event filters are only called for objects that live in the main thread.
OS Specific Keyboard Handling Alternative
If looking at debug statements from a Qt event filter installed at the level mentioned above yields the same results as what you mentioned in your question, then you will need to go to the OS specific keyboard input stuff. For example in Windows you would need to scan the keyboard and or look at the VK state of the whole keyboard and do something with it (with something like GetKeyboardState() ).
I know it's a bit late to answer this question. Still... I have the same problem with Mac key release events and there is an open bug QTBUG-36839.
On Windows you may implement keyboard hook to catch every key presses/releases. But even that is not reliable in some cases. E.g. if you will type lock screen shortcut after unlocking you will NOT see any key release. I guess there must be something similar to hook on Mac. If it is important to you to remember what exactly physical key user pressed - I think this is one of the best ways. At the same time, from my experience, doing something low-level takes a lot of time and may bring a weird bugs in cases you never could imagine. So the question is: are you sure you cannot make what you need with something like QAction?
Or maybe you could just use Control instead of Command in your shortcuts :)

Qt Design Promoted Qpushbutton parameterised constructor

I've been learning about subclassing and widget promotion in Qt Designer and I've promoted some QPushButtons. My promoted class represents the number keys on a calculator, and takes a parameter in the constructor. The parameter given is the number of the button and it is passed in as an int.
Is there a way to tell Qt Designer how to construct each button? The constructor needs the numbers 0-9 passed to it. If I manually modify the generated code it works; however, each time it generates the form, I have to manually edit it.
There is no simple way to achieve this while keeping your argument in the constructor I'm afraid (read this page in the docs to how you might go about it).
I think your best solution is to keep the constructor mirroring that of QPushButton (i.e. just passing a parent QWidget) and set your custom data by calling a function afterwards.

How can I stop Qt::ForbiddenCursor from appearing during a drag?

I'm implementing a drag and drop interface with Qt across X11 and Windows. The interface handles events such that it is not illegal for a user to drop a dragged object on an area which can't handle drops.
In this case, Qt::IgnoreAction should therefore not be treated as an incorrect potential action. To communicate this fact to the user I need a way to stop Qt::ForbiddenCursor from displaying if the current Qt::DropAction is Qt::IgnoreAction.
There are three ways I can see to achieve this (in order of preference):
To override the QCursor used for a drag with Qt::IgnoreAction to something other than Qt::ForbiddenCursor.
To override the bitmap used for Qt::ForbiddenCursor. This is pretty dirty but would be an acceptable solution as long as I don't have to delve into OS-specific configuration.
To override the call made by Qt when a drag leaves a valid drop area (I assume that Qt does the equivalent of QDropEvent::setDropAction(Qt::IgnoreAction) in this case).
Could anyone suggest ways to acheive any of the above?
Note: I have also attempted to use QApplication::setOverrideCursor() just before calling QDrag::exec(). This doesn't seem to have any effect.
Check if QDragEnterEvent comes to application itself (install event filter on QApplication object). If it does, simply accept it and cursor will appear normal.

QGrahicsItem and their children

I have now tried for hours to make sense of how QGraphicsItem behaves with respect to children. I create a new QGraphicsItem B (actually an own subclass of it), and then add it to another QGraphicsItem A as child by invoking the setParentItem method on B. Immediately after that A has B as child. I have verified with some debug code that iterates over the children of A. Then A is added to a List of As in a Manager. Some time later in the program, in a QWidget the lists iterator is obtained from the manager. I then iterate over the list of As and check the children for each of them and all of them are gone. I have verified in the debugger that the Manager is really the same instance and the list is also the same instance. Somehow this really puzzles me, who in the Qt FWK decides for me that my A objects do no longer need their children?
I'm a newby to Qt and C++, also with extensive development experience from java to objective-c so I have some hope it is a speciality of Qt I'm not aware of, not entirely my own stupidity...
Best Regards,
André
FYI:
QGraphicsItemGroup specially designed for grouping.
// Group all selected items together
QGraphicsItemGroup *group = scene->createItemGroup(scene->selecteditems());

Updating a QListView when objects change externally

I've a simple question regarding the update of a QTreeView (or any subclass of QAbstractItemView) when a model object changes externally. Let's say that a list shows a subclass of QAbstractItemModel, and an item of that model gets changed outside of the list window, and we would like to update the list with the change. What is the usual strategy to achieve something like this ? I've looked at the Qt documentation of QAbstractItemModel and there is a signal named 'dataChanged' that is (or should be) emited when data from the model changes. But since this signal (as all QAbstractItemModel functions/signals/slots) work with a QModelIndex, which is not persistent as the documentation clearly says, am i supposed to store somehow a mapping of my data to QPersistentModelIndex(es), so when my data change i will be able to find the corresponding QPersistenModelIndex and use that as argument to the various QAbstractItemModel functions ? Is that what QPersistentModelIndex(es) are used for ? Or am i missing something ?
Thank you.
ps: I guess i could just reload the QTreeView, but then i wouldn't know which items were expanded or which were selected. Is there an strategy to overcome this problem and just reload the list ?
QTreeView already handles the case in which the underlying model's data changed (i.e. the model has emitted the dataChanged() signal). That means you don't need to do any additional work on the view.
If you're implementing your own model (a derived class of QAbstractItemView), and you're making a change to the contents of the model, you simply need to emit the dataChanged() signal when your change is complete. The signal/slot mechanism will automatically inform the view using that signal.

Resources