QSqlRelationalTableModel with QSqlRelationalDelega

2019-08-26 09:03发布

问题:

I need to swap the rows and columns of a QSqlRelationalTableModel. After a lot of searching, I wrote a little proxymodel to flip the rows and the columns.

It is partly working. The relations in the table are resolved and showed but the dropboxes to choose them gets lost. Also, how do I get them to update?

Here is a little self-contained script that reproduces the behavior.

Where is my error? I have strong suspicion that it has to do with the signals and slots of the models but I haven't found any hint which ones and how to reimplement them.

Is there another easier way to swap rows and columns?

EDIT: to clarify the delegational model isn't completely not working its just partial working.

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_())

回答1:

big thanks to some friendly stranger on the #pyqt irc. this is solved.

the answer is that the delegates also need an proxymodel class.

the class looks like:

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)

its used then replacing the delegates as:

view.setItemDelegate(FlipProxyDelegate(self.tableView))