【问题标题】:Multiple models crash多个模型崩溃
【发布时间】:2014-09-27 02:30:01
【问题描述】:

下面的代码创建了一个窗口,其中QListView 在左侧,QTableView 在右侧。 使用.setModel() QListView 被分配ListModelQTableView 被分配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_()) 

【问题讨论】:

  • 你能提供更多的崩溃细节吗?它发生在代码的哪一行?
  • 在 OSX:10.7.5,Python:2.7.1,Qt:5.2.0,SIP:4.15.4,PyQt:4.10.4 上,它会在左侧列表中立即崩溃-视图的项目被点击。
  • 你正在使用 Qt5 和 PyQt4?除非您只是打错了字,否则这似乎并不明智……

标签: python qt pyqt


【解决方案1】:

我无法在 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 行(第二行)等。

  • TableModel.data() 方法已损坏。具体来说,它似乎缺少key=str(self.items[index.row()])

  • 这一行

我的问题是,由于您似乎经常遇到模型问题(我觉得我在这里看到了很多关于实现自定义模型的问题),您为什么不使用预定义的Qt 模型QStandardItemModel 为您完成所有复杂的工作? (你不需要继承它来使用它)

如果您需要帮助将上面发布的示例翻译成使用QStandardItemModel,请发布一个新问题。我相信我或其他人会很快回答。

【讨论】:

  • 感谢您的澄清。我一直在使用.beginInsertRows(parent, first_row_number_to_insert, last_row_number_to_insert) 错误。我认为最后一个 arg 应该是一个列。知道它我已经修复了一个代码。它现在就像一个魅力!再次感谢!
  • 几天前,我在QStandardItemModel:stackoverflow.com/a/25985721/1107049 上发表了一篇文章,我喜欢“它为我做了所有复杂的事情”。使用“QtCore.QAbstractTableModel”我试图避免QStandardItemModel 施加的可能限制。因为“我会为你做所有复杂的事情”模式可能会带来一些副作用。不是吗?
  • 我刚刚发布了一个问题,这是对这里开始内容的逻辑延续。问题的链接:stackoverflow.com/q/26067068/1107049 听听您的意见会很有趣。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-02-21
  • 2021-03-07
  • 2016-12-11
  • 2018-01-18
  • 1970-01-01
  • 1970-01-01
  • 2021-10-03
相关资源
最近更新 更多