QSqlRelationalTableModel с QSqlRelationalDelegate не работает за QAbstractProxyModel
Мне нужно поменять местами строки и столбцы QSqlRelationalTableModel. После долгих поисков я написал небольшую прокси-модель для переворачивания строк и столбцов.
Это частично работает. Отношения в таблице разрешены и показаны, но выпадающие списки для их выбора теряются. Кроме того, как мне заставить их обновить?
Вот небольшой автономный скрипт, который воспроизводит поведение.
Где моя ошибка? У меня есть сильное подозрение, что это связано с сигналами и слотами моделей, но я не нашел ни одного намека на то, какие из них и как их переопределить.
Есть ли другой способ поменять местами строки и столбцы?
РЕДАКТИРОВАТЬ: чтобы уточнить делегативную модель не совсем не работает, это просто частичная работа.
from PySide import QtCore, QtGui, QtSql
from PySide.QtCore import Qt, QModelIndex
from PySide.QtGui import QAbstractProxyModel, QWidget, QHBoxLayout, QTableView
from PySide.QtSql import QSqlRelationalDelegate
class FlipProxyModel(QAbstractProxyModel):
def __init__(self, parent=None):
super(FlipProxyModel, self).__init__(parent)
def mapFromSource(self, index):
return self.createIndex(index.column(), index.row())
def mapToSource(self, index):
return self.sourceModel().index(index.column(), index.row(), QModelIndex())
def columnCount(self, parent):
return self.sourceModel().rowCount(QModelIndex())
def rowCount(self, parent):
return self.sourceModel().columnCount(QModelIndex())
def index(self, row, column, parent):
return self.createIndex(row, column)
def parent(self, index):
# tables have no parent object so return empty
return QModelIndex()
def data(self, index, role):
return self.sourceModel().data(self.mapToSource(index), role)
def headerData(self, section, orientation, role):
if orientation == Qt.Horizontal:
return self.sourceModel().headerData(section, Qt.Vertical, role)
if orientation == Qt.Vertical:
return self.sourceModel().headerData(section, Qt.Horizontal, role)
def createConnection():
db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName(":memory:")
if not db.open():
print 'fatal'
return False
return True
def createView(title, model):
view = QtGui.QTableView()
view.setModel(model)
view.setItemDelegate(QtSql.QSqlRelationalDelegate(view))
view.setWindowTitle(title)
return view
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
if not createConnection():
sys.exit(1)
# createRelationalTables()
query = QtSql.QSqlQuery()
query.exec_("create table employee(id int, name varchar(20), city int, country int)")
query.exec_("insert into employee values(1, 'Espen', 5000, 47)")
query.exec_("insert into employee values(2, 'Harald', 80000, 49)")
query.exec_("insert into employee values(3, 'Sam', 100, 41)")
query.exec_("create table city(id int, name varchar(20))")
query.exec_("insert into city values(100, 'San Jose')")
query.exec_("insert into city values(5000, 'Oslo')")
query.exec_("insert into city values(80000, 'Munich')")
query.exec_("create table country(id int, name varchar(20))")
query.exec_("insert into country values(41, 'USA')")
query.exec_("insert into country values(47, 'Norway')")
query.exec_("insert into country values(49, 'Germany')")
model = QtSql.QSqlRelationalTableModel()
model.setTable("employee")
model.setEditStrategy(QtSql.QSqlTableModel.OnManualSubmit)
model.setRelation(2, QtSql.QSqlRelation('city', 'id', 'name'))
model.setRelation(3, QtSql.QSqlRelation('country', 'id', 'name'))
model.setHeaderData(0, QtCore.Qt.Horizontal, "ID")
model.setHeaderData(1, QtCore.Qt.Horizontal, "Name")
model.setHeaderData(2, QtCore.Qt.Horizontal, "City")
model.setHeaderData(3, QtCore.Qt.Horizontal, "Country")
model.select()
proxy = FlipProxyModel()
proxy.setSourceModel(model)
w = QWidget()
layout = QHBoxLayout(w)
view = QTableView()
view.setModel(model)
view.setItemDelegate(QSqlRelationalDelegate(view))
layout.addWidget(view)
view2 = QTableView()
view2.setModel(proxy)
view2.setItemDelegate(QSqlRelationalDelegate(view2))
layout.addWidget(view2)
w.show()
sys.exit(app.exec_())
2 ответа
Большое спасибо дружелюбному незнакомцу на #pyqt irc. это решено
Ответ заключается в том, что делегатам также нужен класс proxymodel.
класс выглядит так:
class FlipProxyDelegate(QSqlRelationalDelegate):
def createEditor(self, parent, option, index):
proxy = index.model()
base_index = proxy.mapToSource(index)
return super(FlipProxyDelegate, self).createEditor(parent, option, base_index)
def setEditorData(self, editor, index):
proxy = index.model()
base_index = proxy.mapToSource(index)
return super(FlipProxyDelegate, self).setEditorData(editor, base_index)
def setModelData(self, editor, model, index):
base_model = model.sourceModel()
base_index = model.mapToSource(index)
return super(FlipProxyDelegate, self).setModelData(editor, base_model, base_index)
его используют, а затем заменяют делегатов как:
view.setItemDelegate(FlipProxyDelegate(self.tableView))
Я бы предложил расширенную версию решения @logsoft , чтобы обрабатывать делегатов независимо от того, есть прокси или нет.
class ExtendedRelationalDelegate(QSqlRelationalDelegate):
"""This customization allows to handle also sql models behind Proxy"""
@staticmethod
def base_model(model: QAbstractItemModel):
if isinstance(model, QAbstractProxyModel):
return model.sourceModel()
return model
@staticmethod
def base_index(index: QModelIndex):
if isinstance(index.model(), QAbstractProxyModel):
return index.model().mapToSource(index)
return index
def createEditor(self, parent, option, index):
return QSqlRelationalDelegate.createEditor(self, parent, option, self.base_index(index))
def setEditorData(self, editor, index: QModelIndex):
return QSqlRelationalDelegate.setEditorData(self, editor, self.base_index(index))
def setModelData(self, editor, model, index):
return QSqlRelationalDelegate.setModelData(self, editor, self.base_model(model), self.base_index(index))