Nominate our 2022 Qt Champions!

"keyPressEvent" is (sometimes) not called after DragDrop

  • Hello,
    i want to drag items from a table, but only when i press ALT.
    Without i want only easy selection.

    My solution:
    void Cxy::keyPressEvent(QKeyEvent *event)
    { if(event->key() == Qt::Key_Alt) { gotable->setDragEnabled(true); }
    void Cxy::keyReleaseEvent(QKeyEvent *event)
    { if(event->key() == Qt::Key_Alt) { gotable->setDragEnabled(false); }

    works, but i often loose "keyReleaseEvent" when i drop the content in another program.
    My solution: a retriggered timer till the windows function "GetKeyState" says "no more ALT". Works perfect.

    But i still have a problem with "keyPressEvent".
    This works fine: (A) 1. press ALT, 2. drag 3. drop 4. release ALT
    This also: (B) 1. press ALT 2. drag 3. release ALT 4. drop in another program (my program looses focus)
    This also: (C) 1. press ALT 2. drag 3. release ALT 4. drop in my own program

    BUT, in case (C) qt don't call "keyPressEvent" when i press ALT next time.
    In this single case i have to press ALT 2 times, only the second time i get a "keyPressEvent"
    I even can press other keys, they are detected(!), but when i press ALT after (C) (and even after pressing other keys), the first pressed ALT has no effect.
    Seems that only the ALT key is locked once after (C).

    Any idea?
    I could use "GetKeyState" again, but then i have to poll it permanently and waste many cpu-time...

  • I guess, when Drag is in progress, Qt does not provide key-events at all.

    Seems that key-handling is not the the main strenght from Qt, so i wrote my own key-handler by using
    original windows funktion SetWindowsHookEx(WH_KEYBOARD_LL, myLowLevelKeyboardProc, NULL, 0);
    Not portable, of course, but it works perfect in all cases without the need to program timers etc.
    But i am still open for better soulutions...

  • Moderators

    a way cleaner approach instead of toggling the drag-enabled property like you do, would be to override QAbstractItemView::startDrag() and check if the ALT key is pressed - using QApplication::keyboardModifiers().

    Assuming Cxy is subclassing QAbstractItemView

    void Cxy::startDrag(Qt::DropActions supportedActions)
        if( !(QApplication::keyboardModifiers() & Qt::AltModifier) )
        QModelIndexList selectedIndexes = this->getSelectedDraggableIndexes();  // need to be implemented by yourself
        if (selectedIndexes .count() > 0)
            QMimeData *data = this->model()->mimeData(selectedIndexes);
            if ( !data )
            QDrag *drag = new QDrag(this);
            Qt::DropAction defaultDropAction = Qt::IgnoreAction;
            if (this->defaultDropAction() != Qt::IgnoreAction && (supportedActions & this->defaultDropAction()))
                defaultDropAction = this->defaultDropAction();
            else if (supportedActions & Qt::CopyAction && dragDropMode() != QAbstractItemView::InternalMove)
                defaultDropAction = Qt::CopyAction;
            drag->exec(supportedActions, defaultDropAction);

  • Hello @raven-worx ,
    thank you very much for this hint.
    First you confused me a little bit with "subclassing QAbstractItemView".
    I didn't find how to subclass "QAbstractItemView".
    In effect, i only had to extended "myQTableWidget"
    in Header:
    bool useAltKey; // DragDrop with ALT on/off
    void startDrag(Qt::DropActions supportedActions);
    and in implementation:
    void myQTableWidget::startDrag(Qt::DropActions supportedActions)
    { if( useAltKey && (!(QApplication::keyboardModifiers() & Qt::AltModifier)) ) { return; }
    QTableWidget::startDrag( supportedActions);

    Works perfect, and it's even easier to turn on/off this feature. Again thank you.

  • Moderators

    indeed...this is easier. :)

Log in to reply