Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

selectionChanged() not called when item selected with setCurrentIndex() is deselected



  • I move through a QListView with Previous and Next buttons. I do this with setCurrentIndex(), using the currently selected index +/-1, and QItemSelectionModel::SelectCurrent.

    However, if the item is deselected with CTRL+click, selectionChanged() is not emitted as it is if I had clicked on the item and then deselected. So, how can I select an item in the list such that it is the same as if I had clicked on it?


  • Lifetime Qt Champion

    Hi,

    So you move the selection with your button and then "unselect" it with the mouse and this does not trigger the signal ?



  • @SGaist

    That is correct.
    If I select the item by clicking on it and then deselecting, it works fine.

    The index to select the next item is calculated: index(selection.indexes().at(0).row() + 1, 0)


  • Lifetime Qt Champion

    Which version of Qt are you using ?

    Can you provide a minimal compilable example that shows this behaviour ?



  • Using Qt_5_13_1. I'm using a custom model and delegate and QSortFilterProxyModel.
    Just tried reproducing using QStringListModel and it woks fine. Not really sure where I should be looking.



  • I notice that using the keyboard arrow keys works, so I could replicate the way in which they make a selection, if you know how that's done? Also important to point out that deselecting the item does "un-highlight" it, so clearly the deselection is being registered somewhere.



  • @SGaist,

    I've written a test application which demonstrates this behaviour. How/where can I host this? Looks like the forum doesn't allow attachments.


  • Lifetime Qt Champion

    Create a bug report, attach the testcase.
    But since the example should not be longer than 50 lines (at least I would expect this from your description) and doesn't need a ui file you can also paste it here (don't forget the code tags!)



  • @SGaist @Christian-Ehrlicher ,

    The problem appears to be related to the use of QSortFilterProxyModel. The following example uses QStringListModel and QSortFilterProxyModel for sorting in ascending order:

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <QStringList>
    #include <QStringListModel>
    #include <QAbstractItemView>
    
    QT_BEGIN_NAMESPACE
    namespace Ui { class MainWindow; }
    QT_END_NAMESPACE
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    
        void newSelection(const QItemSelection &selected, const QItemSelection &deselected);
    
    private slots:
        void on_add_clicked();
    
        void on_insert_clicked();
    
        void on_delete_2_clicked();
    
    
    
        void on_selectItem2_clicked();
    
    private:
        Ui::MainWindow *ui;
        QStringListModel *model;
    };
    #endif // MAINWINDOW_H
    
    
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    #include <QSortFilterProxyModel>
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        // Create model
            model = new QStringListModel(this);
    
            // Make data
            QStringList List;
            List << "Clair de Lune" << "Reverie" << "Prelude";
    
            // Populate our model
            model->setStringList(List);
    
            // Glue model and view together
            ui->listView->setModel(model);
            ui->comboBox->setModel(model);
            QSortFilterProxyModel* proxy = new QSortFilterProxyModel();
            proxy->setSourceModel(model);
            proxy->setSortRole(Qt::DisplayRole);
            proxy->setDynamicSortFilter(true);
            ui->listView->setModel(proxy);
            proxy->sort(0);
    
            // Add additional feature so that
            // we can manually modify the data in ListView
            // It may be triggered by hitting any key or double-click etc.
            ui->listView->
                    setEditTriggers(QAbstractItemView::AnyKeyPressed |
                                    QAbstractItemView::DoubleClicked);
            QItemSelectionModel* selectionModel = ui->listView->selectionModel();
            connect(selectionModel, &QItemSelectionModel::selectionChanged, this, &MainWindow::newSelection);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    
    void MainWindow::on_add_clicked()
    {
        // Add button clicked
            // Adding at the end
    
            // Get the position
            int row = model->rowCount();
    
            // Enable add one or more rows
            model->insertRows(row,1);
    
            // Get the row for Edit mode
            QModelIndex index = model->index(row);
    
            // Enable item selection and put it edit mode
            ui->listView->setCurrentIndex(index);
            ui->listView->edit(index);
    }
    
    void MainWindow::on_insert_clicked()
    {
        // Insert button clicked
    
            // Get the position
            int row = ui->listView->currentIndex().row();
    
            // Enable add one or more rows
            model->insertRows(row,1);
    
            // Get row for Edit mode
            QModelIndex index = model->index(row);
    
            // Enable item selection and put it edit mode
            ui->listView->setCurrentIndex(index);
            ui->listView->edit(index);
    }
    
    void MainWindow::on_delete_2_clicked()
    {
        // Delete button clicked
            // For delete operation,
            // we're dealing with a Model not a View
            // Get the position
            model->removeRows(ui->listView->currentIndex().row(),1);
    }
    
    void MainWindow::newSelection(const QItemSelection &selected, const QItemSelection &deselected){
    
        int x = 5; //Enter new Selection
    }
    
    void MainWindow::on_selectItem2_clicked()
    {
        QItemSelection selection = ui->listView->selectionModel()->selection();
        QModelIndex index = model->index(1, 0);
        ui->listView->selectionModel()->clearSelection();
        ui->listView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
    }
    
    
    <?xml version="1.0" encoding="UTF-8"?>
    <ui version="4.0">
     <class>MainWindow</class>
     <widget class="QMainWindow" name="MainWindow">
      <property name="geometry">
       <rect>
        <x>0</x>
        <y>0</y>
        <width>661</width>
        <height>360</height>
       </rect>
      </property>
      <property name="windowTitle">
       <string>MainWindow</string>
      </property>
      <widget class="QWidget" name="centralwidget">
       <widget class="QWidget" name="">
        <property name="geometry">
         <rect>
          <x>90</x>
          <y>20</y>
          <width>258</width>
          <height>251</height>
         </rect>
        </property>
        <layout class="QGridLayout" name="gridLayout_2">
         <item row="0" column="0">
          <widget class="QListView" name="listView"/>
         </item>
         <item row="1" column="0">
          <layout class="QGridLayout" name="gridLayout">
           <item row="0" column="2">
            <widget class="QPushButton" name="delete_2">
             <property name="text">
              <string>Delete</string>
             </property>
            </widget>
           </item>
           <item row="2" column="0" colspan="3">
            <widget class="QComboBox" name="comboBox"/>
           </item>
           <item row="0" column="1">
            <widget class="QPushButton" name="insert">
             <property name="text">
              <string>Insert</string>
             </property>
            </widget>
           </item>
           <item row="0" column="0">
            <widget class="QPushButton" name="add">
             <property name="text">
              <string>Add</string>
             </property>
            </widget>
           </item>
           <item row="1" column="0" colspan="3">
            <widget class="QPushButton" name="selectItem2">
             <property name="text">
              <string>Select Item 2</string>
             </property>
            </widget>
           </item>
          </layout>
         </item>
        </layout>
       </widget>
      </widget>
      <widget class="QMenuBar" name="menubar">
       <property name="geometry">
        <rect>
         <x>0</x>
         <y>0</y>
         <width>661</width>
         <height>21</height>
        </rect>
       </property>
      </widget>
      <widget class="QStatusBar" name="statusbar"/>
     </widget>
     <resources/>
     <connections/>
    </ui>
    
    

    To test, set a breakpoint in the newSelection() slot. Run in debug mode and press "Select Item 2". Notice then, that when you "unselect" with CTRL+Click, the slot is not entered (presumably the selectionChanged() signal is not emitted).



  • Can someone please confirm if this is a Qt bug before I file a bug report?


  • Lifetime Qt Champion

    Here are readable minimal example which is working:

    #include <QtWidgets>
    
    class MainWindow : public QWidget
    {
    public:
      MainWindow(QWidget *parent = nullptr);
      void newSelection(const QItemSelection &selected, const QItemSelection &deselected);
      void onSelectItem();
      QListView *lv;
    };
    
    MainWindow::MainWindow(QWidget *parent)
      : QWidget(parent)
    {
      QVBoxLayout *lay = new QVBoxLayout(this);
      lv = new QListView(this);
      lay->addWidget(lv);
      auto pb = new QPushButton("Select item 2");
      lay->addWidget(pb);
    
      auto model = new QStringListModel({"Clair de Lune", "Reverie", "Prelude"}, this);
      auto proxy = new QSortFilterProxyModel(this);
      proxy->setSortRole(Qt::DisplayRole);
      proxy->setDynamicSortFilter(true);
      proxy->setSourceModel(model);
      proxy->sort(0);
      lv->setModel(proxy);
    
      // Add additional feature so that
      // we can manually modify the data in ListView
      // It may be triggered by hitting any key or double-click etc.
      lv->setEditTriggers(QAbstractItemView::AnyKeyPressed |
                          QAbstractItemView::DoubleClicked);
      QItemSelectionModel* selectionModel = lv->selectionModel();
      connect(selectionModel, &QItemSelectionModel::selectionChanged, this, &MainWindow::newSelection);
    
      connect(pb, &QPushButton::clicked, this, &MainWindow::onSelectItem);
    }
    
    void MainWindow::newSelection(const QItemSelection &selected, const QItemSelection &deselected)
    {
      qDebug() << "selectionChanged, selected:" << selected << ", deselected:" << deselected;
    }
    
    void MainWindow::onSelectItem()
    {
      QItemSelection selection = lv->selectionModel()->selection();
      QModelIndex index = lv->model()->index(1, 0);
      lv->selectionModel()->clearSelection();
      lv->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
    }
    
    int main(int argc, char **argv)
    {
      QApplication app(argc, argv);
    
      MainWindow mw;
      mw.show();
      return app.exec();
    }
    
    

    You use the wrong model in your MainWindow::on_selectItem2_clicked() slot.


Log in to reply