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. How to intercept View-based widgets item selection with ability for user to cancel it

How to intercept View-based widgets item selection with ability for user to cancel it

Scheduled Pinned Locked Moved Unsolved General and Desktop
8 Posts 2 Posters 1.1k 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.
  • L Offline
    L Offline
    levolex
    wrote on last edited by levolex
    #1

    Hello everyone!

    Recently I faced a problem in implementing some common UI feature. For example I have a form where user can edit some model through a standart view widget. But right before he selects another row (or cell) there should be some validation checks and in some conditions show a confirmation dialog for the user. If he pushes "Ok"-button selection should happen, othewise selection should be canceled.

    The most obvious solution seemed to me was interception of mouse click events (using eventFilter() method), but the problem is that there is no mouse click events neither in eventFilter(), not in event() methods. I looked in a Qt sources but still doesn`t fugure who receives this mouse events.

    Then I tried to reimplement QListView::selectionCommand() method. I succeed to cancel selection, but here was a problem that the method is constant, so I'm able to show user confirmation dialog but cant do any actions there (in my case submiting changes to server).

    The third way I tried to solve the problem was to set some custom selection model (derived from QItemSelectionModel). It seemed to be the most proper way, cause user can select items (and rows) in many ways (mouse click, keyboard..). But there I faced a problem with infinite loop of showing dialog window.

    For now I found the only workaround to reimplement mousePressEvent() and keyPressEvent() in a class derived from QListView. I find this code messy. And more now I faced the same problem with QCalendarWidget, and here view-object is incapsulated so I cant substitute it with a custom one.

    What I`m doing wrong? It looks to me like a common UI task, so I believe it should be some simple elegant way to implement such features.

    1 Reply Last reply
    0
    • VRoninV Offline
      VRoninV Offline
      VRonin
      wrote on last edited by
      #2

      You are overcomplicating it. you just need to connect(view->itemSelectionModel(),&QItemSelectionModel::selectionChanged to a slot that does the check and decides what to do with the selections

      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
      ~Napoleon Bonaparte

      On a crusade to banish setIndexWidget() from the holy land of Qt

      1 Reply Last reply
      2
      • L Offline
        L Offline
        levolex
        wrote on last edited by
        #3

        You mean select previous item back instead of prevent the selection? For now it seems to me as this solution can have some unwanted side effects, because selection signal is often connected with some slots with visual changes (like loading row values of the model to widgets by QDataWidgetMapper etc.) so frequent selection can result in interface flickering, or am I wrong?

        Anyway thank you for the answer, I will try and check your way.

        VRoninV 1 Reply Last reply
        0
        • L levolex

          You mean select previous item back instead of prevent the selection? For now it seems to me as this solution can have some unwanted side effects, because selection signal is often connected with some slots with visual changes (like loading row values of the model to widgets by QDataWidgetMapper etc.) so frequent selection can result in interface flickering, or am I wrong?

          Anyway thank you for the answer, I will try and check your way.

          VRoninV Offline
          VRoninV Offline
          VRonin
          wrote on last edited by
          #4

          @levolex said in How to intercept View-based widgets item selection with ability for user to cancel it:

          so frequent selection can result in interface flickering

          If the slot is run on the GUI thread and connected with Qt::DirectConnection then the visual updates of selection gets aggregated into 1 by Qt automatically and no flickering should occur

          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
          ~Napoleon Bonaparte

          On a crusade to banish setIndexWidget() from the holy land of Qt

          L 1 Reply Last reply
          0
          • VRoninV VRonin

            @levolex said in How to intercept View-based widgets item selection with ability for user to cancel it:

            so frequent selection can result in interface flickering

            If the slot is run on the GUI thread and connected with Qt::DirectConnection then the visual updates of selection gets aggregated into 1 by Qt automatically and no flickering should occur

            L Offline
            L Offline
            levolex
            wrote on last edited by
            #5

            @VRonin I tried to connect my slot to QItemSelectionModel::selectionChanged. It works but only with some workarounds. If I call QItemSelectionModel::select() in the connected slot it results in infinite loop of selection (and stack overflow error), so I used boolean variable to avoid it. But anyway it doesn't work if I have QMessageBox::question in the slot to control selection process.

            So this slot code is working (preventing selection):

            void MainWidget::onSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
            {
                if (_isCanceling || deselected.isEmpty())
                    return;
            
                QItemSelectionRange prevRange = deselected.first();
                QItemSelection selection(prevRange.topLeft(), prevRange.bottomRight());
                _isCanceling = true;
                ui->listView->selectionModel()->select(selection, QItemSelectionModel::ClearAndSelect);
                _isCanceling = false;
            }
            

            This doesn't:

            void MainWidget::onSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
            {
                if (_isCanceling || deselected.isEmpty())
                    return;
            
                bool allowed = QMessageBox::question(this, "Confirmation", "Allow selection?");
                if (!allowed) {
                    QItemSelectionRange prevRange = deselected.first();
                    QItemSelection selection(prevRange.topLeft(), prevRange.bottomRight());
                    _isCanceling = true;
                    ui->listView->selectionModel()->select(selection, QItemSelectionModel::ClearAndSelect);
                    _isCanceling = false;
                }
            }
            

            Thank you in advance.

            1 Reply Last reply
            0
            • VRoninV Offline
              VRoninV Offline
              VRonin
              wrote on last edited by
              #6

              What part doesn't work?

              "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
              ~Napoleon Bonaparte

              On a crusade to banish setIndexWidget() from the holy land of Qt

              L 1 Reply Last reply
              0
              • VRoninV VRonin

                What part doesn't work?

                L Offline
                L Offline
                levolex
                wrote on last edited by
                #7

                @VRonin This:

                ui->listView->selectionModel()->select(selection, QItemSelectionModel::ClearAndSelect);
                

                It doen't select previous item.

                1 Reply Last reply
                0
                • VRoninV Offline
                  VRoninV Offline
                  VRonin
                  wrote on last edited by VRonin
                  #8

                  QMessageBox::question does not return a boolean.

                  replace

                  bool allowed = QMessageBox::question(this, "Confirmation", "Allow selection?");
                  if (!allowed)
                  

                  With

                  const QMessageBox::StandardButton allowed = QMessageBox::question(this, "Confirmation", "Allow selection?");
                  if (allowed == QMessageBox::No)
                  

                  "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                  ~Napoleon Bonaparte

                  On a crusade to banish setIndexWidget() from the holy land of Qt

                  1 Reply Last reply
                  3

                  • Login

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