Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Keystroke is forwarded unintentionally

Keystroke is forwarded unintentionally

Scheduled Pinned Locked Moved Solved General and Desktop
13 Posts 4 Posters 470 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • D Offline
    D Offline
    django.Reinhard
    wrote on last edited by
    #1

    Hi,

    my application is developed keyboard-centric and so I check which widget has the focus when I press a key. A function is then called accordingly.

    If a standard dialog is operated with keyboard (i.e. the button is activated by ENTER key), then the keystroke still reaches the keyboard handler, although the dialog has already processed the button.

    Qt_Message03.jpg

    Can the keyboard-/event-buffer be cleared in the function in which the standard dialog is used, so that the keystroke is not evaluated incorrectly?

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      Are you using exec to show your dialog ? If so, switch to open and use slots for result handling.

      Exec spins a second event loop and you may experience unexpected behaviour.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      0
      • D Offline
        D Offline
        django.Reinhard
        wrote on last edited by
        #3

        Hi,

        I just use QMessageBox::question( ... )

        do you have a sample, that uses standarddialogs with open and slots?

        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          In this case you can use the buttonClicked signal to know what happened.

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          0
          • D Offline
            D Offline
            django.Reinhard
            wrote on last edited by
            #5

            Hi,

            guess I have to go back to school again - nobody understands my writing :(

            @SGaist said in Keystroke is forwarded unintentionally:

            ... to know what happened.

            I already know, what happened.

            In the screenshot usecase the delete key with focus at tableview was pressed, which raises this dialog. When the user selects "No" button (cursor right) and presses Enter, then the delete operation aborts.
            ... but then the edit operation starts (which is bound to Enter key with focus at tableview). When edit starts, the standard dialog has already been removed ...

            But when enter was pressed, the dialog had the focus and not the tableview. So the event forwarding is faulty, as the action is already processed.

            So that's going wrong, and I'm looking for a way to get out of that trap.

            If it is possible to clear event-queue programmatically, best point is imho the function that calls QMessageBox::question

            1 Reply Last reply
            0
            • C Offline
              C Offline
              ChrisW67
              wrote on last edited by
              #6

              @django-Reinhard said in Keystroke is forwarded unintentionally:

              So that's going wrong, and I'm looking for a way to get out of that trap.

              If your view has QAbstractItemView::AnyKeyPressed as its edit trigger then the Delete you started with probably put the cell into edit mode before your dialog blocked the event loop of the main program. It stays in that mode when your dialog is dismissed.
              Hard to say for sure... we cannot see your code or "keyboard handler" or how the plumbing is done. Guessing is what we are left with.

              D 1 Reply Last reply
              0
              • C ChrisW67

                @django-Reinhard said in Keystroke is forwarded unintentionally:

                So that's going wrong, and I'm looking for a way to get out of that trap.

                If your view has QAbstractItemView::AnyKeyPressed as its edit trigger then the Delete you started with probably put the cell into edit mode before your dialog blocked the event loop of the main program. It stays in that mode when your dialog is dismissed.
                Hard to say for sure... we cannot see your code or "keyboard handler" or how the plumbing is done. Guessing is what we are left with.

                D Offline
                D Offline
                django.Reinhard
                wrote on last edited by
                #7

                @ChrisW67 said in Keystroke is forwarded unintentionally:

                if your view has QAbstractItemView::AnyKeyPressed as its edit trigger

                Well, not intentionally. Don't know, what default is, but I don't use intable editing. Editor is the widget at the lower right.

                @ChrisW67 said in Keystroke is forwarded unintentionally:

                Hard to say for sure... we cannot see your code or "keyboard handler" or how the plumbing is done. Guessing is what we are left with.

                Yes, you're absolutely right! My fault.

                My code is available.

                excerpts from it ...

                Keyboard handler:

                void ToolManager::keyReleaseEvent(QKeyEvent *event) {
                  switch (event->key()) {
                    case KeyCodes::Enter:
                         if (tools->hasFocus()) editTool();
                         break;
                         ...
                    case KeyCodes::Insert: {
                         if (categories->hasFocus()) createCategory();
                         else if (tools->hasFocus()) createTool();
                         } break;
                    case KeyCodes::Delete: {
                         if (categories->hasFocus()) deleteCategory();
                         else if (tools->hasFocus()) deleteTool();
                         } break;
                    case KeyCodes::F6_Key: {
                         if (categories->hasFocus()) renameCategory();
                         } break;
                    case KeyCodes::F10_Key:
                         if (tEdit->isEnabled()) saveToolChanges();
                         break;
                    }
                  event->setAccepted(true);
                  }
                

                ... delete-Function:

                void ToolManager::deleteTool() {
                  qDebug() << "delete tool: " << toolModel->record(tool2Edit).value("num");
                  QMessageBox::StandardButton reply;
                
                  reply = QMessageBox::question(this
                                              , tr("QMessageBox::question()")
                                              , tr("Should this tool be deleted?")
                                              , QMessageBox::Yes | QMessageBox::No);
                  if (reply == QMessageBox::No) return;
                  if (!toolModel->removeRows(tool2Edit, 1)) qDebug() << toolModel->lastError().text();
                  if (!toolModel->submitAll())              qDebug() << toolModel->lastError().text();
                  }
                

                ... and edit-Function:

                void ToolManager::editTool() {
                  categories->hide();
                  tools->hide();
                  tEdit->setEnabled(true);
                
                  // fill all space inside QScrollarea
                  if (edSize.width() == -1 && edSize.height() == -1) edSize = tEdit->size();
                  tEdit->resize(size().width() - 20, size().height() - 20);
                
                  // data record is already loaded into editor,
                  // so just inform about how to finish editing
                  QMessageBox::information(this
                                         , tr("QMessageBox::information()")
                                         , tr("To finish tool editing press F10 "
                                              "to save changes or ESC to abort."));
                  }
                
                
                1 Reply Last reply
                0
                • D Offline
                  D Offline
                  django.Reinhard
                  wrote on last edited by
                  #8

                  Hi,

                  I did some further tests, but situation does not look any nicer.

                  I tried to patch Qt like this:

                  void QPushButton::keyPressEvent(QKeyEvent *e)
                  {
                      Q_D(QPushButton);
                      switch (e->key()) {
                      case Qt::Key_Enter:
                      case Qt::Key_Return:
                          if (autoDefault() || d->defaultButton) {
                              e->setAccepted(true);                     // added 4 test
                              click();
                              break;
                          }
                          Q_FALLTHROUGH();
                      default:
                          QAbstractButton::keyPressEvent(e);
                      }
                  }
                  

                  which worked fine in debugging session, but failed in release code.
                  So I guessed, it is a timing issue, but adding some sleep did not change anything either.

                  so I tried to check timestamp of keyEvent - but against all logic keyEvent that arrives my widget class has newer timestamp, than timestamp when messagebox got closed ...

                  So I tried to use EventFilter - but - cursor right arrives the filter, but Enter that triggered the button did not arrive the filter.

                  I also tried to use a modified messagebox, that uses open instead of exec - but on open no dialog window appeared.

                  Actually I run out of ideas.

                  debug logs prints this:

                  • before mb::exec
                  • Messagebox finished ...
                  • after mb::exec - myTS: 12197200
                  • TM: enter ( 16777220 ) has ts: 12197346
                  • myTS: 12197350

                  "before mb::exec" is originated in delete-function, just before calling exec of the messagebox

                  "Messagebox finished" is printed by the callback, connected to messagebox::finished

                  "after mb::exec" is printed from delete-function, after closing the messagebox. So the Enter-keypress has happened before that timestamp (myTS).

                  "TM: enter" is printed from keyboard-handler of the main widget (parent of treeview, tableview and editor).

                  Last message "myTS" is the timestamp printed from keyboard-handler when release of Enter-key has been detected.

                  So even if event routing might be ok, timestamp refresh is definitely NOT ok. And as QEvent does not contain the widget, that had the focus when the key was pressed, I don't know, how to solve that trap.

                  Any hint is appreciated!

                  1 Reply Last reply
                  1
                  • mrjjM Offline
                    mrjjM Offline
                    mrjj
                    Lifetime Qt Champion
                    wrote on last edited by
                    #9

                    Hi

                    For test, could you use this function

                    void MainWindow::deleteTool()
                    {
                        QMessageBox *msgBox = new QMessageBox(this);
                        msgBox->setText("QMessageBox::question()");
                        msgBox->setInformativeText("Should this tool be deleted?");
                        msgBox->setStandardButtons(QMessageBox::Yes | QMessageBox::No);
                        msgBox->setDefaultButton(QMessageBox::Yes);
                        msgBox->setIcon(QMessageBox::Question);
                       // handle answer
                        connect(msgBox, &QMessageBox::buttonClicked, this, [this, msgBox](QAbstractButton * button) {
                            if ( msgBox->button(QMessageBox::StandardButton::Yes) == button )
                                qDebug() << "Yes to the dress"; // youcan use this->toolModel->xxxx
                            msgBox->deleteLater();
                        });
                      
                        msgBox->open();
                    }
                    
                    

                    and see if return still bleeds through as then we know it is indeed a side effect of the exec() / local event loop.

                    1 Reply Last reply
                    0
                    • D Offline
                      D Offline
                      django.Reinhard
                      wrote on last edited by django.Reinhard
                      #10

                      Hi,

                      thank you for your attention!

                      I changed your code to this:

                        QMessageBox *msgBox = new QMessageBox(this);
                      
                        msgBox->setText("QMessageBox::question()");
                        msgBox->setInformativeText("Should this tool be deleted?");
                        msgBox->setStandardButtons(QMessageBox::Yes | QMessageBox::No);
                        msgBox->setDefaultButton(QMessageBox::Yes);
                        msgBox->setIcon(QMessageBox::Question);
                      
                        // handle answer
                        connect(msgBox, &QMessageBox::buttonClicked
                              , this, [this, msgBox](QAbstractButton * button) {
                                        if (msgBox->button(QMessageBox::StandardButton::Yes) == button)
                                           qDebug() << "Yes to the dress"; // youcan use this->toolModel->xxxx
                                        else
                                           qDebug() << "No - don't drop this";
                                        qDebug() << "from mb::callback - myTS:" << timeStamp();
                                        msgBox->deleteLater();
                                        });
                        msgBox->open();
                      

                      ... and the same happens.
                      Debug log shows:

                      No - don't drop this
                      from mb::callback - myTS: 1068270
                      TM: enter ( 16777220 ) has ts:  1068408
                      myTS: 1068410
                      

                      I updated my repo, in case you want debug.

                      Just to clarify things: usecase is:

                      • select a tool (in tableview)
                      • hit delete key (which opens the messagebox)
                      • hit cursor right to change focus from "Yes" to "No"
                      • hit Enter to activate the button

                      then editor starts with tool detail data, started from keyboard-handler keyRelease and Enter-key.

                      I thought I had similar code.
                      Could someone please explain me, why in my case nothing happens, when I call msgBox->open() ?

                      My code looks like:

                      QMessageBox* MessageBox::showMessage(QWidget *parent
                                                        , QMessageBox::Icon icon
                                                        , const QString &title
                                                        , const QString &text
                                                        , const QString &button0Text
                                                        , const QString &button1Text
                                                        , const QString &button2Text
                                                        , int
                                                        , int ) {
                        mb = new QMessageBox(icon, title, text, QMessageBox::NoButton, parent);
                        QString myButton0Text = button0Text;
                      
                        if (myButton0Text.isEmpty())
                           myButton0Text = QDialogButtonBox::tr("OK");
                      
                        mb->addButton(myButton0Text, QMessageBox::ActionRole);
                        if (!button1Text.isEmpty()) mb->addButton(button1Text, QMessageBox::ActionRole);
                        if (!button2Text.isEmpty()) mb->addButton(button2Text, QMessageBox::ActionRole);
                      //  const QList<QAbstractButton *> &buttonList = messageBox.d_func()->customButtonList;
                      
                      //  messageBox.setDefaultButton(static_cast<QPushButton *>(buttonList.value(defaultButtonNumber)));
                      //  messageBox.setEscapeButton(buttonList.value(escapeButtonNumber));
                      
                        connect(mb, &QMessageBox::finished, this, &MessageBox::finished);
                      //  messageBox.exec();
                        return mb;
                        }
                      
                      
                      QMessageBox* MessageBox::question(QWidget* parent, const QString& title, const QString& text) {
                        return showMessage(parent, QMessageBox::Question, title, text, tr("Yes"), tr("No"), QString());
                        }
                      
                      
                      void MessageBox::finished() {
                        qDebug() << "Messagebox finished ...";
                        }
                      

                      In ToolManager::delete I had this code:

                        MessageBox   mb;
                        QMessageBox* qmb = mb.question(this
                                                    , tr("QMessageBox::question()")
                                                    , tr("Should this tool be deleted?"));
                      
                      //  qmb->installEventFilter(this);
                      
                        qDebug() << "before mb::exec";
                        qmb->exec();
                        qDebug() << "after mb::exec - myTS:" << timeStamp();
                      
                        return;
                      

                      I tried qmb->open() but nothing happened.
                      Therefore I got back to qmb->exec().

                      mrjjM 1 Reply Last reply
                      0
                      • D django.Reinhard

                        Hi,

                        thank you for your attention!

                        I changed your code to this:

                          QMessageBox *msgBox = new QMessageBox(this);
                        
                          msgBox->setText("QMessageBox::question()");
                          msgBox->setInformativeText("Should this tool be deleted?");
                          msgBox->setStandardButtons(QMessageBox::Yes | QMessageBox::No);
                          msgBox->setDefaultButton(QMessageBox::Yes);
                          msgBox->setIcon(QMessageBox::Question);
                        
                          // handle answer
                          connect(msgBox, &QMessageBox::buttonClicked
                                , this, [this, msgBox](QAbstractButton * button) {
                                          if (msgBox->button(QMessageBox::StandardButton::Yes) == button)
                                             qDebug() << "Yes to the dress"; // youcan use this->toolModel->xxxx
                                          else
                                             qDebug() << "No - don't drop this";
                                          qDebug() << "from mb::callback - myTS:" << timeStamp();
                                          msgBox->deleteLater();
                                          });
                          msgBox->open();
                        

                        ... and the same happens.
                        Debug log shows:

                        No - don't drop this
                        from mb::callback - myTS: 1068270
                        TM: enter ( 16777220 ) has ts:  1068408
                        myTS: 1068410
                        

                        I updated my repo, in case you want debug.

                        Just to clarify things: usecase is:

                        • select a tool (in tableview)
                        • hit delete key (which opens the messagebox)
                        • hit cursor right to change focus from "Yes" to "No"
                        • hit Enter to activate the button

                        then editor starts with tool detail data, started from keyboard-handler keyRelease and Enter-key.

                        I thought I had similar code.
                        Could someone please explain me, why in my case nothing happens, when I call msgBox->open() ?

                        My code looks like:

                        QMessageBox* MessageBox::showMessage(QWidget *parent
                                                          , QMessageBox::Icon icon
                                                          , const QString &title
                                                          , const QString &text
                                                          , const QString &button0Text
                                                          , const QString &button1Text
                                                          , const QString &button2Text
                                                          , int
                                                          , int ) {
                          mb = new QMessageBox(icon, title, text, QMessageBox::NoButton, parent);
                          QString myButton0Text = button0Text;
                        
                          if (myButton0Text.isEmpty())
                             myButton0Text = QDialogButtonBox::tr("OK");
                        
                          mb->addButton(myButton0Text, QMessageBox::ActionRole);
                          if (!button1Text.isEmpty()) mb->addButton(button1Text, QMessageBox::ActionRole);
                          if (!button2Text.isEmpty()) mb->addButton(button2Text, QMessageBox::ActionRole);
                        //  const QList<QAbstractButton *> &buttonList = messageBox.d_func()->customButtonList;
                        
                        //  messageBox.setDefaultButton(static_cast<QPushButton *>(buttonList.value(defaultButtonNumber)));
                        //  messageBox.setEscapeButton(buttonList.value(escapeButtonNumber));
                        
                          connect(mb, &QMessageBox::finished, this, &MessageBox::finished);
                        //  messageBox.exec();
                          return mb;
                          }
                        
                        
                        QMessageBox* MessageBox::question(QWidget* parent, const QString& title, const QString& text) {
                          return showMessage(parent, QMessageBox::Question, title, text, tr("Yes"), tr("No"), QString());
                          }
                        
                        
                        void MessageBox::finished() {
                          qDebug() << "Messagebox finished ...";
                          }
                        

                        In ToolManager::delete I had this code:

                          MessageBox   mb;
                          QMessageBox* qmb = mb.question(this
                                                      , tr("QMessageBox::question()")
                                                      , tr("Should this tool be deleted?"));
                        
                        //  qmb->installEventFilter(this);
                        
                          qDebug() << "before mb::exec";
                          qmb->exec();
                          qDebug() << "after mb::exec - myTS:" << timeStamp();
                        
                          return;
                        

                        I tried qmb->open() but nothing happened.
                        Therefore I got back to qmb->exec().

                        mrjjM Offline
                        mrjjM Offline
                        mrjj
                        Lifetime Qt Champion
                        wrote on last edited by
                        #11

                        @django-Reinhard

                        Hmm so it seems its not due to using exec()

                        If I want to run your code, I have to call/run setupDb first ?

                        1 Reply Last reply
                        0
                        • D Offline
                          D Offline
                          django.Reinhard
                          wrote on last edited by
                          #12

                          Yes, its a separate pro-file, which creates and populates the database.

                          1 Reply Last reply
                          0
                          • D Offline
                            D Offline
                            django.Reinhard
                            wrote on last edited by
                            #13

                            Just to close this:

                            I added a timecode check and this way I could sort out the unwanted/wrong keyevent.

                            1 Reply Last reply
                            1

                            • Login

                            • Login or register to search.
                            • First post
                              Last post
                            0
                            • Categories
                            • Recent
                            • Tags
                            • Popular
                            • Users
                            • Groups
                            • Search
                            • Get Qt Extensions
                            • Unsolved