QTableView中的虚拟列?

2024-04-25 23:36:33 发布

您现在位置:Python中文网/ 问答频道 /正文

我开始学习Qt4模型/视图编程,我有一个初学者的问题。在

我有一个简单的应用程序,在QTableView中显示sqlite表:

class Model(QtSql.QSqlTableModel):
    def __init__(self, parent=None):
        super(Model, self).__init__(parent)
        self.setEditStrategy(QtSql.QSqlTableModel.OnFieldChange)

        self.setTable("test")
        self.select()

class App(QtGui.QMainWindow):
    def __init__(self, model):
        QtGui.QMainWindow.__init__(self)

        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self.ui.tableView.setModel(model)

if __name__ == "__main__":
    myDb = QtSql.QSqlDatabase.addDatabase("QSQLITE")
    myDb.setDatabaseName("test.db")

    if not myDb.open():
        print 'FIXME'

    model = Model()

    app = QtGui.QApplication(sys.argv)
    window = App(model)
    window.show()
    sys.exit(app.exec_())

以下是数据库的外观:

^{pr2}$

所以我得到的东西是:

+---+---+-----+
| a | b |  c  |
+---+---+-----+
| 1 | 2 | xxx |
+---+---+-----+
| 6 | 7 | yyy |
+---+---+-----+

是否可以将Model修改为在QTableView中具有类似于虚拟列的内容?例如:

+---+---+-----+-----+
| a | b | sum |  c  |
+---+---+-----+-----+
| 1 | 2 |  3  | xxx |
+---+---+-----+-----+
| 6 | 7 | 13  | yyy |
+---+---+-----+-----+

或者我应该用别的方法做?在


Tags: testselfappuimodelinitdefclass
3条回答

是的,你可以的。虽然@BrtH's answer是相关的,但是模型很复杂,很容易丢失。所以我认为一个更典型的例子会更好。在

就个人而言,我会使用从QAbstractProxyModel派生的代理模型。但是,在您的例子中,重新实现QSqlTableModel也是可行的。下面是您的目标实现。请注意,了解Model/View methodology的基本知识是非常重要的,这样才能理解每个方法的作用。在

class Model(QtSql.QSqlTableModel):
    def __init__(self, parent=None):
        super(Model, self).__init__(parent)
        self.setEditStrategy(QtSql.QSqlTableModel.OnFieldChange)

        self.setTable("test")
        self.select()


    def columnCount(self, parent=QtCore.QModelIndex()):
        # this is probably obvious
        # since we are adding a virtual column, we need one more column
        return super(Model, self).columnCount()+1


    def data(self, index, role=QtCore.Qt.DisplayRole):
        if role == QtCore.Qt.DisplayRole and index.column()==2:
            # 2nd column is our virtual column.
            # if we are there, we need to calculate and return the value
            # we take the first two columns, get the data, turn it to integer and sum them
            # [0] at the end is necessary because pyqt returns value and a bool
            # http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/qvariant.html#toInt
            return sum(self.data(self.index(index.row(), i)).toInt()[0] for i in range(2))
        if index.column() > 2:
            # if we are past 2nd column, we need to shift it to left by one
            # to get the real value
            index = self.index(index.row(), index.column()-1)
        # get the value from base implementation
        return super(Model, self).data(index, role)


    def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
        # this is similar to `data`
        if section==2 and orientation==QtCore.Qt.Horizontal and role==QtCore.Qt.DisplayRole:
            return 'Sum'
        if section > 2 and orientation==QtCore.Qt.Horizontal:
            section -= 1
        return super(Model, self).headerData(section, orientation, role)


    def flags(self, index):
        # since 2nd column is virtual, it doesn't make sense for it to be Editable
        # other columns can be Editable (default for QSqlTableModel)
        if index.column()==2:
            return QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled
        return QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable


    def setData(self, index, data, role):
        # similar to data.
        # we need to be careful when setting data (after edit)
        # if column is after 2, it is actually the column before that
        if index.column() > 2:
            index = self.index(index.row(), index.column()-1)
        return super(Model, self).setData(index, data, role)

你看过QSqlQueryModel了吗? 它允许显示任何SQL查询的结果。示例代码:

class Model(QtSql.QSqlQueryModel):
    def __init__(self, parent=None):
        super(Model, self).__init__(parent)
        self.setQuery("SELECT a, b, a + b, c FROM test")
        self.setHeaderData(0, QtCore.Qt.Horizontal, "a")
        self.setHeaderData(1, QtCore.Qt.Horizontal, "b")
        self.setHeaderData(2, QtCore.Qt.Horizontal, "sum")
        self.setHeaderData(3, QtCore.Qt.Horizontal, "c")

但请记住:

The model is read-only by default. To make it read-write, you must subclass it and reimplement setData() and flags().

这是很有可能的。下面是我自己的一些代码的示例,为您的数据修改。在

import sqlite3

conn = sqlite3.connect('test.db')


class MyTreeModel(QAbstractItemModel):
    def __init__(self, parent=None):
        super(MyTreeModel, self).__init__(parent)

        c = conn.cursor()
        c.execute("SELECT a, b, c FROM 'test'")
        self.items = c.fetchall()

        self.columns = ['a', 'b', 'sum', 'c']

    def columnCount(self, index):
        return len(self.columns)

    def rowCount(self, parent):
        return len(self.items)

    def data(self, index, role=Qt.DisplayRole):
        if index.isValid():
            col= index.column()
            spot = self.items[index.row()]
            if role == Qt.DisplayRole:
                if col == 0 or col == 1:
                    return self.items[index.row()][col]
                elif col == 2:
                    return self.items[index.row()][0] + self.items[index.row()][1]
                elif col == 3:
                    return self.items[index.row()][2]

    def headerData(self, section, orientation, role=Qt.DisplayRole):
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            return self.columns[section]

    def index(self, row, col, index):
        if not index.isValid():
            return self.createIndex(row, col)
        else:
            return QModelIndex()

    def parent(self, child):
        return QModelIndex()

这是一个QTreeView的模型,但我认为您可以很容易地适应它。
有关这些方法和模型的更多信息,请参见http://srinikom.github.com/pyside-docs/PySide/QtCore/QAbstractItemModel.html。在

相关问题 更多 >

    热门问题