PySide:QAbstractItemModel 不与简单控件对话
PySide: QAbstractItemModel not talking to simple controls
我正在尝试使用 PySide 将多个数据控件连接到我从光盘读取的文件中的数据。所以我做了一个数据模型,派生自 QAbstractItemModel。应该是微不足道的,对吧?但是我遇到的一个问题是连接 QLineEdit 和 QTextEdit 控件以显示并允许编辑模型中的数据。
根据 QT 文档中的 Simple Widget Mapper 和 Combo Widget Mapper 等示例,我相信我必须有一个包含一行的数据模型,以及一个 QWidgetMapper 来将该行中的单元格连接到编辑控件.
这是一个非常精简的程序,它显示了这个问题。本例中的数据模型returns 三个字符串x1、x2 和x3。字符串从例如更改为"First (1)" 到 "First (2)" 通过调用更新,即通过单击 "Next" 按钮。那就是模拟从文件或任何地方读取的新值。主要 window 有几个 QLineEdits 和一个 QTextEdit,映射器应该 link 到模型数据。但是数据没有显示在编辑控件中。
为了检查模型,我添加了一个 QTableView。数据在那里显示正常,并在单击 "Next" 时更新,因此它不是数据模型。它介于那里和编辑控件之间。但是我看不到我没有在做什么,小部件映射器示例在做什么。
我做错了什么?
顺便说一句,走另一条路也不行。如果我向模型添加一个 setData() 方法,并发出 dataChanged,则在行编辑中输入的更改会到达 Table。但即使发生这种情况,该项目也会从行编辑中消失。单击 "Next" 后,QLineEdit 和 QTextEdit 将停止工作——不再调用 setData()。但是,如果我在 table 视图中进行编辑,setData 仍会被调用。
示例代码如下:
#!/usr/bin/python
import sys
from PySide.QtCore import ( Qt, QAbstractItemModel,QModelIndex
)
from PySide.QtGui import ( QApplication, QMainWindow, QPushButton, QWidget,
QTextEdit, QLineEdit, QFormLayout, QTableView,
QDataWidgetMapper,
)
##############################################################################
class TModel(QAbstractItemModel):
"""
This model will have 1 row of 3 items
There will be a slot that will change the items. If they are displayed
in widgets, I want to see them update.
"""
def __init__(self, parent=None):
super(TModel, self).__init__(parent)
self.counter = 0
self.x1 = ""
self.x2 = ""
self.x3 = ""
self.Update()
def columnCount(self, index=QModelIndex()):
return 3
def rowCount(self, index=QModelIndex()):
return 1
def index(self, row, column, index=QModelIndex()):
if not self.hasIndex(row, column, index):
return QModelIndex()
return self.createIndex(row, column)
def parent(self, index):
return QModelIndex()
def hasChildren(self, index):
return False
def data(self, index, role=Qt.DisplayRole):
if index.isValid():
if role == Qt.DisplayRole:
if index.column() == 0:
return self.x1
elif index.column() == 1:
return self.x2
elif index.column() == 2:
return self.x3
return None
def headerData(self, section, orientation, role):
if role != Qt.DisplayRole:
return None
if orientation == Qt.Horizontal:
if section == 0:
return "col 1"
elif section == 1:
return "col 2"
elif section == 2:
return "col 3"
def Update(self):
self.beginResetModel()
self.x1 = "First (%d)"%self.counter
self.x2 = "Second (%d)"%self.counter
self.x3 = "Third (%d)"%self.counter
self.counter += 1
self.endResetModel()
##############################################################################
class TMainWindow(QMainWindow):
"""Main GUI object"""
def __init__(self, parent=None):
super(TMainWindow, self).__init__(parent)
self.DataModel = TModel()
self.Mapper = QDataWidgetMapper()
self.Mapper.setSubmitPolicy(self.Mapper.AutoSubmit)
self.Mapper.setModel(self.DataModel)
self.FirstFieldEdit = QLineEdit()
self.SecondFieldEdit = QLineEdit()
self.ThirdFieldEdit = QTextEdit()
self.Mapper.addMapping(self.FirstFieldEdit, 0)
self.Mapper.addMapping(self.SecondFieldEdit, 1)
self.Mapper.addMapping(self.ThirdFieldEdit, 2)
self.Mapper.toFirst()
self.UpdateButton = QPushButton("Next")
self.UpdateButton.clicked.connect(self.DataModel.Update)
formLayout = QFormLayout()
formLayout.addRow("&First:", self.FirstFieldEdit)
formLayout.addRow("&Second:", self.SecondFieldEdit)
formLayout.addRow("&Third:", self.ThirdFieldEdit)
formLayout.addRow("", self.UpdateButton)
self.testTable = QTableView()
self.testTable.setModel(self.DataModel)
formLayout.addRow("Table:", self.testTable)
W = QWidget()
W.setLayout(formLayout)
self.setCentralWidget(W)
##############################################################################
if __name__ == "__main__":
app = QApplication(sys.argv)
MainWindow = TMainWindow()
MainWindow.show()
sys.exit(app.exec_())
QDataWidgetMapper
class 旨在允许在模型中显示和编辑记录。但是当请求数据进行编辑时,您的模型不会 return 任何东西。所以一个简单的修复是:
def data(self, index, role=Qt.DisplayRole):
if index.isValid():
if role == Qt.DisplayRole or role == Qt.EditRole:
...
编辑:
来自 Qt 文档:
QDataWidgetMapper can be used to create data-aware widgets by mapping
them to sections of an item model. A section is a column of a model if
the orientation is horizontal (the default), otherwise a row. [emphasis added]
我建议您避免尝试编写自定义模型(除了最简单的情况,这远非微不足道),并从使用 QStandardItemModel.
开始
我正在尝试使用 PySide 将多个数据控件连接到我从光盘读取的文件中的数据。所以我做了一个数据模型,派生自 QAbstractItemModel。应该是微不足道的,对吧?但是我遇到的一个问题是连接 QLineEdit 和 QTextEdit 控件以显示并允许编辑模型中的数据。
根据 QT 文档中的 Simple Widget Mapper 和 Combo Widget Mapper 等示例,我相信我必须有一个包含一行的数据模型,以及一个 QWidgetMapper 来将该行中的单元格连接到编辑控件.
这是一个非常精简的程序,它显示了这个问题。本例中的数据模型returns 三个字符串x1、x2 和x3。字符串从例如更改为"First (1)" 到 "First (2)" 通过调用更新,即通过单击 "Next" 按钮。那就是模拟从文件或任何地方读取的新值。主要 window 有几个 QLineEdits 和一个 QTextEdit,映射器应该 link 到模型数据。但是数据没有显示在编辑控件中。
为了检查模型,我添加了一个 QTableView。数据在那里显示正常,并在单击 "Next" 时更新,因此它不是数据模型。它介于那里和编辑控件之间。但是我看不到我没有在做什么,小部件映射器示例在做什么。
我做错了什么?
顺便说一句,走另一条路也不行。如果我向模型添加一个 setData() 方法,并发出 dataChanged,则在行编辑中输入的更改会到达 Table。但即使发生这种情况,该项目也会从行编辑中消失。单击 "Next" 后,QLineEdit 和 QTextEdit 将停止工作——不再调用 setData()。但是,如果我在 table 视图中进行编辑,setData 仍会被调用。
示例代码如下:
#!/usr/bin/python
import sys
from PySide.QtCore import ( Qt, QAbstractItemModel,QModelIndex
)
from PySide.QtGui import ( QApplication, QMainWindow, QPushButton, QWidget,
QTextEdit, QLineEdit, QFormLayout, QTableView,
QDataWidgetMapper,
)
##############################################################################
class TModel(QAbstractItemModel):
"""
This model will have 1 row of 3 items
There will be a slot that will change the items. If they are displayed
in widgets, I want to see them update.
"""
def __init__(self, parent=None):
super(TModel, self).__init__(parent)
self.counter = 0
self.x1 = ""
self.x2 = ""
self.x3 = ""
self.Update()
def columnCount(self, index=QModelIndex()):
return 3
def rowCount(self, index=QModelIndex()):
return 1
def index(self, row, column, index=QModelIndex()):
if not self.hasIndex(row, column, index):
return QModelIndex()
return self.createIndex(row, column)
def parent(self, index):
return QModelIndex()
def hasChildren(self, index):
return False
def data(self, index, role=Qt.DisplayRole):
if index.isValid():
if role == Qt.DisplayRole:
if index.column() == 0:
return self.x1
elif index.column() == 1:
return self.x2
elif index.column() == 2:
return self.x3
return None
def headerData(self, section, orientation, role):
if role != Qt.DisplayRole:
return None
if orientation == Qt.Horizontal:
if section == 0:
return "col 1"
elif section == 1:
return "col 2"
elif section == 2:
return "col 3"
def Update(self):
self.beginResetModel()
self.x1 = "First (%d)"%self.counter
self.x2 = "Second (%d)"%self.counter
self.x3 = "Third (%d)"%self.counter
self.counter += 1
self.endResetModel()
##############################################################################
class TMainWindow(QMainWindow):
"""Main GUI object"""
def __init__(self, parent=None):
super(TMainWindow, self).__init__(parent)
self.DataModel = TModel()
self.Mapper = QDataWidgetMapper()
self.Mapper.setSubmitPolicy(self.Mapper.AutoSubmit)
self.Mapper.setModel(self.DataModel)
self.FirstFieldEdit = QLineEdit()
self.SecondFieldEdit = QLineEdit()
self.ThirdFieldEdit = QTextEdit()
self.Mapper.addMapping(self.FirstFieldEdit, 0)
self.Mapper.addMapping(self.SecondFieldEdit, 1)
self.Mapper.addMapping(self.ThirdFieldEdit, 2)
self.Mapper.toFirst()
self.UpdateButton = QPushButton("Next")
self.UpdateButton.clicked.connect(self.DataModel.Update)
formLayout = QFormLayout()
formLayout.addRow("&First:", self.FirstFieldEdit)
formLayout.addRow("&Second:", self.SecondFieldEdit)
formLayout.addRow("&Third:", self.ThirdFieldEdit)
formLayout.addRow("", self.UpdateButton)
self.testTable = QTableView()
self.testTable.setModel(self.DataModel)
formLayout.addRow("Table:", self.testTable)
W = QWidget()
W.setLayout(formLayout)
self.setCentralWidget(W)
##############################################################################
if __name__ == "__main__":
app = QApplication(sys.argv)
MainWindow = TMainWindow()
MainWindow.show()
sys.exit(app.exec_())
QDataWidgetMapper
class 旨在允许在模型中显示和编辑记录。但是当请求数据进行编辑时,您的模型不会 return 任何东西。所以一个简单的修复是:
def data(self, index, role=Qt.DisplayRole):
if index.isValid():
if role == Qt.DisplayRole or role == Qt.EditRole:
...
编辑:
来自 Qt 文档:
QDataWidgetMapper can be used to create data-aware widgets by mapping them to sections of an item model. A section is a column of a model if the orientation is horizontal (the default), otherwise a row. [emphasis added]
我建议您避免尝试编写自定义模型(除了最简单的情况,这远非微不足道),并从使用 QStandardItemModel.
开始