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.
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
.