#python #pyside2 #qtableview
#python #pyside2 #qtableview
Вопрос:
Как я могу сохранить выделение элементов при сортировке таблицы? В приведенном ниже примере выделение всегда привязано к индексу строки, т.Е. Если я выбираю первую строку, то после сортировки всегда выбирается первая строка, а не фактическая строка, которую я выбрал.
import sys
from PySide2 import QtWidgets, QtGui, QtCore
from PySide2.QtCore import Qt
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, data):
super().__init__()
self._data = data
def data(self, index, role):
if role == Qt.DisplayRole:
return self._data[index.row()][index.column()]
def sort(self, column, order):
if order == Qt.DescendingOrder:
rev = True
else:
rev = False
self.layoutAboutToBeChanged.emit()
self._data.sort(key=lambda x: x[column], reverse=rev)
self.layoutChanged.emit()
def rowCount(self, parent=None):
return len(self._data)
def columnCount(self, parent=None):
return len(self._data[0])
class Main(QtWidgets.QDialog):
def __init__(self, data):
super().__init__()
self.layout = QtWidgets.QVBoxLayout()
self.table = QtWidgets.QTableView()
self.table.setSortingEnabled(True)
self.table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows)
self.model = TableModel(data)
self.table.setModel(self.model)
self.layout.addWidget(self.table)
self.setLayout(self.layout)
def main():
app = QtWidgets.QApplication(sys.argv)
data = [
[1,2,3,4],
[5,6,7,8],
[6,5,4,3],
[2,1,0,9]
]
m = Main(data)
m.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Ответ №1:
При реализации метода сортировки вы изменяете данные, и представление не может узнать новое положение элементов, вместо изменения данных вы должны изменить индексы с помощью QSortFilterProxyModel:
import sys
from PySide2 import QtCore, QtGui, QtWidgets
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, data):
super().__init__()
self._data = data
def data(self, index, role):
if role == QtCore.Qt.DisplayRole:
return self._data[index.row()][index.column()]
def rowCount(self, parent=None):
return len(self._data)
def columnCount(self, parent=None):
return len(self._data[0])
class Main(QtWidgets.QDialog):
def __init__(self, data):
super().__init__()
self.layout = QtWidgets.QVBoxLayout()
self.table = QtWidgets.QTableView()
self.table.setSortingEnabled(True)
self.table.setSelectionBehavior(
QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows
)
self.model = TableModel(data)
self.proxy = QtCore.QSortFilterProxyModel()
self.proxy.setSourceModel(self.model)
self.table.setModel(self.proxy)
self.layout.addWidget(self.table)
self.setLayout(self.layout)
def main():
app = QtWidgets.QApplication(sys.argv)
data = [[1, 2, 3, 4], [5, 6, 7, 8], [6, 5, 4, 3], [2, 1, 0, 9]]
m = Main(data)
m.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Ответ №2:
В версии Qt 5.15 на C выделение сохраняется, но вам нужно вернуться к нему … что не очень удобно… Чтобы заставить его, вы можете подключить сигнал заголовка QHeaderView::sectionClicked
к слоту в вашем tableview, где что-то вроде этого выполняет эту работу:
// m_tableView being your QTableView you connect the signal in your constructor
connect(m_tableView->horizontalHeader(), amp;QHeaderView::sectionClicked, this, amp;RepliesPage::onSortColumn);
void RepliesPage::onSortColumn(int)
{
auto selected = m_tableView->selectionModel()->selectedIndexes();
if (selected.size())
m_tableView->scrollTo(selected.first());
}
думаю, это довольно близко в python или qml 😉