Unsolved 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?
-
Hi,
So you move the selection with your button and then "unselect" it with the mouse and this does not trigger the signal ?
-
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)
-
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.
-
I've written a test application which demonstrates this behaviour. How/where can I host this? Looks like the forum doesn't allow attachments.
-
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?
-
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.