下面的代码会创建一个左侧为QListView
而右侧为QTableView
的窗口。
使用.setModel()
QListView
分配了ListModel
,QTableView
被分配了TableModel
。
在窗口启动时,只有列表视图会填充项目。只有在单击左侧列表视图时才会填充右表视图。
问题:为什么这段代码会崩溃?是因为两个型号在同一时间使用吗?
import sys, os
from PyQt4 import QtCore, QtGui
app=QtGui.QApplication(sys.argv)
elements={'Animals':{1:'Bison',2:'Panther',3:'Elephant'},'Birds':{1:'Duck',2:'Hawk',3:'Pigeon'},'Fish':{1:'Shark',2:'Salmon',3:'Piranha'}}
class ListModel(QtCore.QAbstractTableModel):
def __init__(self):
QtCore.QAbstractTableModel.__init__(self)
self.items=[]
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.items)
def columnCount(self, index=QtCore.QModelIndex()):
return 1
def data(self, index, role):
if not index.isValid() or not (0<=index.row()<len(self.items)): return QtCore.QVariant()
key=str(self.items[index.row()])
if role==QtCore.Qt.UserRole:
return key
if role==QtCore.Qt.DisplayRole:
return key
def addItem(self, key=None, column=0):
totalItems=self.rowCount()+1
self.beginInsertRows(QtCore.QModelIndex(), totalItems, column)
self.items.append(str(key))
self.endInsertRows()
def buildItems(self):
for key in elements:
self.addItem(key)
class TableModel(QtCore.QAbstractTableModel):
def __init__(self):
QtCore.QAbstractTableModel.__init__(self)
self.items=[]
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.items)
def columnCount(self, index=QtCore.QModelIndex()):
return 4
def data(self, index, role):
if not index.isValid() or not (0<=index.row()<len(self.items)): return QtCore.QVariant()
if role==QtCore.Qt.DisplayRole:
return key
def addItem(self, each=None, column=0):
totalItems=self.rowCount()+1
self.beginInsertRows(QtCore.QModelIndex(), totalItems, column)
self.items.append(str(each))
self.endInsertRows()
def rebuildItems(self, index):
key = index.data(QtCore.Qt.UserRole)
if not key: return
key=str(key.toString())
for each in elements[key]:
self.addItem(str(each))
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
mainLayout=QtGui.QHBoxLayout()
self.setLayout(mainLayout)
self.dataModel=ListModel()
self.dataModel.buildItems()
self.dataModelB=TableModel()
self.viewA=QtGui.QListView()
self.viewA.setModel(self.dataModel)
self.viewA.clicked.connect(self.onClick)
self.viewB=QtGui.QTableView()
self.viewB.setModel(self.dataModelB)
mainLayout.addWidget(self.viewA)
mainLayout.addWidget(self.viewB)
self.show()
def onClick(self, index):
self.viewB.model().rebuildItems(index)
window=Window()
sys.exit(app.exec_())
以下是固定代码。在最初的示例中,问题是由.beginInsertRows()
方法的不当使用引起的。我错误地认为要提供的最后一个参数是列号。但根据文档(感谢three_pineapples指出),最后一个参数应该是要插入的最后一个行号。
import os,sys
from PyQt4 import QtCore, QtGui
app=QtGui.QApplication(sys.argv)
elements={'Animals':{1:'Bison',2:'Panther',3:'Elephant'},'Birds':{1:'Duck',2:'Hawk',3:'Pigeon'},'Fish':{1:'Shark',2:'Salmon',3:'Piranha'}}
class ListModel(QtCore.QAbstractTableModel):
def __init__(self):
QtCore.QAbstractTableModel.__init__(self)
self.items=[]
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.items)
def columnCount(self, index=QtCore.QModelIndex()):
return 1
def data(self, index, role):
if not index.isValid() or not (0<=index.row()<len(self.items)): return QtCore.QVariant()
key=str(self.items[index.row()])
if role==QtCore.Qt.UserRole:
return key
if role==QtCore.Qt.DisplayRole:
return key
def addItem(self, key=None):
self.beginInsertRows(QtCore.QModelIndex(), self.rowCount(), self.rowCount())
self.items.append(str(key))
self.endInsertRows()
def buildItems(self):
for key in elements:
self.addItem(key)
class TableModel(QtCore.QAbstractTableModel):
def __init__(self):
QtCore.QAbstractTableModel.__init__(self)
self.items=[]
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.items)
def columnCount(self, index=QtCore.QModelIndex()):
return 4
def data(self, index, role):
key=str(self.items[index.row()])
column=index.column()
if not index.isValid() or not (0<=index.row()<len(self.items)): return QtCore.QVariant()
if role==QtCore.Qt.DisplayRole:
if not column: return key
else:
print key, column, elements.get(key,{}).get(column)
return elements.get(key,{}).get(column)
def rebuildItems(self, index):
key=index.data(QtCore.Qt.UserRole).toString()
self.beginInsertRows(QtCore.QModelIndex(), self.rowCount(), self.rowCount())
self.items.append(key)
self.endInsertRows()
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
mainLayout=QtGui.QHBoxLayout()
self.setLayout(mainLayout)
self.dataModel=ListModel()
self.dataModel.buildItems()
self.dataModelB=TableModel()
self.viewA=QtGui.QListView()
self.viewA.setModel(self.dataModel)
self.viewA.clicked.connect(self.onClick)
self.viewB=QtGui.QTableView()
self.viewB.setModel(self.dataModelB)
mainLayout.addWidget(self.viewA)
mainLayout.addWidget(self.viewB)
self.show()
def onClick(self, index):
self.viewB.model().rebuildItems(index)
window=Window()
sys.exit(app.exec_())
答案 0 :(得分:2)
我无法在PyQt v4.11.1,32位Python 2.7,Windows 8.1上重现您的崩溃。
但是,你的TableModel实现完全被破坏了,所以可能会解释为什么它在你的Mac上崩溃了?
具体做法是:
beginInsertRows
的签名似乎有误。它没有关注文档here(链接到QAbstractTableModel
页面here)。签名不是beginInsertRows(parent, row, column)
,而是beginInsertRows(parent, row, numRows)
。
要插入的行的值应为self.rowCount()
,因为行索引从0开始。因此,当模型中有0个项目时,将插入到第0行(第一行)。如果模型中有1个项目,则插入第1行(第2行)等。
TableModel.data()
方法已损坏。具体来说,似乎缺少行key=str(self.items[index.row()])
我的问题是,因为你似乎经常遇到模型问题(我觉得我在这里看到很多关于实现自定义模型的问题),为什么不是?你使用预定义的Qt模型QStandardItemModel
为你做了所有复杂的事情吗? (您不需要将其子类化以使用它)
如果您需要帮助翻译上面发布的使用QStandardItemModel
的示例,请发布一个新问题。我确定我或其他人会很快回答。