我有两个QTableViews连接到两个QSortFilterProxyModels,它们只连接到一个源模型(QSqlRelationalTableModel(。
在对任何代理模型进行排序或筛选时,它都会反映在相应的表视图中。但是当我修改其中一个代理模型的头数据(装饰角色(时,它会出现在两个表视图中。
我的问题是,头数据是直接应用于源模型还是仅应用于代理?
我用它创建了一个sqlite示例数据库:
conn = sqlite3.connect('customers.db')
c = conn.cursor()
c.execute("PRAGMA foreign_keys=on;")
c.execute("""CREATE TABLE IF NOT EXISTS provinces (
ProvinceId TEXT PRIMARY KEY,
Name TEXT NOT NULL
)""")
c.execute("""CREATE TABLE IF NOT EXISTS customers (
CustomerId TEXT PRIMARY KEY,
Name TEXT NOT NULL,
ProvinceId TEXT,
FOREIGN KEY (ProvinceId) REFERENCES provinces (ProvinceId)
ON UPDATE CASCADE
ON DELETE RESTRICT
)""")
c.execute("INSERT INTO provinces VALUES ('N', 'Northern')")
c.execute("INSERT INTO provinces VALUES ('E', 'Eastern')")
c.execute("INSERT INTO provinces VALUES ('W', 'Western')")
c.execute("INSERT INTO provinces VALUES ('S', 'Southern')")
c.execute("INSERT INTO provinces VALUES ('C', 'Central')")
c.execute("INSERT INTO customers VALUES ('1', 'customer1', 'N')")
c.execute("INSERT INTO customers VALUES ('2', 'customer2', 'E')")
c.execute("INSERT INTO customers VALUES ('3', 'customer3', 'W')")
c.execute("INSERT INTO customers VALUES ('4', 'customer4', 'S')")
c.execute("INSERT INTO customers VALUES ('5', 'customer5', 'C')")
conn.commit()
conn.close()
这是一个窗口,显示了我在为代理模型应用装饰时的问题:
class Window(QWidget):
def __init__(self):
super().__init__()
self.db = QSqlDatabase.addDatabase("QSQLITE")
self.db.setDatabaseName("customers.db")
self.db.open()
self.model = QSqlRelationalTableModel(self, self.db)
self.model.setTable("customers")
self.model.select()
self.proxy1 = QSortFilterProxyModel()
self.proxy1.setSourceModel(self.model)
self.proxy2 = QSortFilterProxyModel()
self.proxy2.setSourceModel(self.model)
hBox = QHBoxLayout()
self.tblView1 = QTableView()
self.tblView1.setModel(self.proxy1)
self.tblView2 = QTableView()
self.tblView2.setModel(self.proxy2)
hBox.addWidget(self.tblView1)
hBox.addWidget(self.tblView2)
icon = QIcon(QPixmap("Resources/icon.png"))
self.proxy1.setHeaderData(
1, Qt.Orientation.Horizontal, icon, Qt.ItemDataRole.DecorationRole)
widget = QWidget()
widget.setLayout(hBox)
self.setLayout(hBox)
self.show()
def main():
App = QApplication(sys.argv)
window = Window()
sys.exit(App.exec_())
if __name__ == '__main__':
main()
问题是因为proxymodel的setHeaderData方法调用了sourcemodel的setHeaderData,也就是说,它相当于调用sourcemodel的方法,导致它也传播到其他proxymodel。一个可能的解决方案是覆盖代理模型的headerData方法,以便它只在该代理模型中返回所需的值。
import sys
from PyQt5.QtCore import QSortFilterProxyModel, Qt
from PyQt5.QtGui import QIcon, QPixmap
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QTableView, QApplication
from PyQt5.QtSql import QSqlDatabase, QSqlRelationalTableModel
class SortFilterProxyModel(QSortFilterProxyModel):
def headerData(self, section, orientation, role=Qt.DisplayRole):
if (
section == 1
and orientation == Qt.Horizontal
and role == Qt.ItemDataRole.DecorationRole
):
return QIcon(QPixmap("Resources/icon.png"))
return super().headerData(section, orientation, role)
class Window(QWidget):
def __init__(self):
super().__init__()
self.db = QSqlDatabase.addDatabase("QSQLITE")
self.db.setDatabaseName("customers.db")
self.db.open()
self.model = QSqlRelationalTableModel(self, self.db)
self.model.setTable("customers")
self.model.select()
self.proxy1 = SortFilterProxyModel()
self.proxy1.setSourceModel(self.model)
self.proxy2 = QSortFilterProxyModel()
self.proxy2.setSourceModel(self.model)
hBox = QHBoxLayout(self)
self.tblView1 = QTableView()
self.tblView1.setModel(self.proxy1)
self.tblView2 = QTableView()
self.tblView2.setModel(self.proxy2)
hBox.addWidget(self.tblView1)
hBox.addWidget(self.tblView2)
def main():
App = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(App.exec_())
if __name__ == "__main__":
main()