2014-09-26 32 views
0

下面的代码创建一个窗口,左侧为QListView,右侧为QTableView。 使用.setModel()QListView被指定为ListModel并且QTableView被指定为TableModel。 在窗口启动时,只有列表视图会填充项目。只有当左侧列表视图被点击时,右表视图才会被填充。多个模型崩溃

enter image description here

问:为什么这个代码崩溃?是否因为两个模型同时使用?

enter image description here

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_()) 

LATER EDITED:

下面是一个固定的代码。在原始示例中,问题是由于使用方法不当造成的。我错误地认为要提供的最后一个参数是一个列号。但根据文档(感谢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

你能提供更多的崩溃细节吗?它在哪一行代码中发生? – Ezee 2014-09-26 09:39:48

+0

在OSX上:10.7.5,Python:2.7.1,Qt:5.2.0,SIP:4.15.4,PyQt:4.10.4一旦左侧列表视图的项目被点击,它就会崩溃。 – alphanumeric 2014-09-26 17:53:04

+0

你正在用PyQt4使用Qt5吗?除非你只是写错了,这似乎并不明智...... – 2014-09-27 02:34:55

回答

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)

  • 由于行索引从0开始,因此您插入的行的值应为self.rowCount()。因此,当您的模型中有0个项目时,插入行0(第一行)。当您的模型中有1件物品时,您插入第1行(第二排)等。

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

我的问题是,既然你似乎相当经常有高配车型的麻烦(我觉得我已经看到你在这里的许多问题,在关于实施一个自定义模型),为什么你不使用预定义的Qt模型QStandardItemModel,它为你做所有复杂的东西? (你不需要继承它来使用它)

如果你想帮助翻译你上面发布的例子到使用QStandardItemModel,请发布一个新问题。我相信我或其他人会很快回答。

+0

感谢您的澄清。我一直在使用'.beginInsertRows(parent,first_row_number_to_insert,last_row_number_to_insert)'错误。我认为最后的arg应该是一个专栏。知道它我已经修复了一个代码。它现在就像一个魅力!再次感谢! – alphanumeric 2014-09-26 18:27:52

+0

前几天我做了'QStandardItemModel'对我采取的一个帖子:http://stackoverflow.com/a/25985721/1107049我喜欢“它所有的复杂的东西给我。”使用'QtCore.QAbstractTableModel'我试图避免'QStandardItemModel'强加的可能的限制。由于“我会为你做所有复杂的事情”模式可能会带来一些副作用。不是吗? – alphanumeric 2014-09-26 18:40:20

+0

我刚刚发布了一个问题,这是从这里开始的逻辑延续。一个问题的链接:http://stackoverflow.com/q/26067068/1107049听到你的意见会很有趣。 – alphanumeric 2014-09-26 20:00:12