Stefan Scherfke
Stefan Scherfke

Reputation: 3222

(Py)Qt5: How to update selection when current item has been set programatically

Usecase: I have a QListWidget. When the user selects any row, I want to reset the current item and selection to row 3:

from PyQt5.QtWidgets import QApplication, QListWidget

app = QApplication([])
l = QListWidget()
l.setSelectionMode(QListWidget.SingleSelection)
l.addItems(list('abcde'))

def slot(current, previous):
    # sm = l.selectionModel()
    l.blockSignals(True)
    l.setCurrentRow(3)
    l.blockSignals(False)
    # sm.select(l.currentIndex(), sm.Select)  # Does not work
    # sm.setCurrentIndex(l.currentIndex(), sm.Select)  # Does not work

l.currentItemChanged.connect(slot)
l.show()
app.exec()

The example above sets row three as current row but keeps the selected row to the one that the user clicked. I already tried various combinations of QItemModel.select() and QItemModel.setCurrentIndex() and similar stuff, but nothing worked. I also found no answers on Google or the Qt forums.

Upvotes: 2

Views: 1204

Answers (1)

eyllanesc
eyllanesc

Reputation: 243907

Using blockSignals in this case is a double-edged sword because I think you're using it to avoid an infinite loop. but this also does not generate that the model is updated, besides that it is unnecessary since setCurrentRow() only updates if it is different from its previous value avoiding that problem.

The solution is to use QTimer.singleShot() to update the change:

import sys
from functools import partial
from PyQt5.QtWidgets import QApplication, QListWidget
from PyQt5.QtCore import QTimer


app = QApplication(sys.argv)
l = QListWidget()
l.setSelectionMode(QListWidget.SingleSelection)
l.addItems(list('abcde'))

row = 3

def onCurrentRowChanged():
    QTimer.singleShot(0, partial(l.setCurrentRow, row))

l.currentRowChanged.connect(onCurrentRowChanged)
l.show()
sys.exit(app.exec_())

Note: the logic does not change if the currentRowChanged signal is changed to currentItemChanged.

Upvotes: 5

Related Questions