我有一个带有QAbstractTableModel和多个QStyledItemDelegates的QTableView。
我通过setStyledItemForColumn来设置这些委托人。
在这种情况下,我的应用程序崩溃了。
当我按下1个键,或者试图将gui向右展开时,就会发生崩溃。
但如果我使用其中一个键,我的应用程序就会正常运行。
我想这是一个Qt bug。
你知道吗?
from PySide2 import QtWidgets
from PySide2 import QtCore
from PySide2 import QtGui
from PySide2 import QtSql
import os
import PySide2
import sys
dirname = os.path.dirname(PySide2.__file__)
plugin_path = os.path.join(dirname, 'plugins', 'platforms')
os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
alphabet = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O"]
class IconDelegate(QtWidgets.QStyledItemDelegate):
def initStyleOption(self, option, index):
super(IconDelegate, self).initStyleOption(option, index)
if option.features & QtWidgets.QStyleOptionViewItem.HasDecoration:
s = option.decorationSize
s.setWidth(option.rect.width())
option.decorationSize = s
class Delegate(QtWidgets.QStyledItemDelegate):
def __init__(self, parent=None):
super(Delegate, self).__init__(parent=None)
def initStyleOption(self, option, index):
# super(IconDelegate, self).initStyleOption(option, index)
if index.column() == 6:
if option.features & QtWidgets.QStyleOptionViewItem.HasDecoration:
s = option.decorationSize
s.setWidth(option.rect.width())
option.decorationSize = s
def createEditor(self, parent, option, index):
editor = QtWidgets.QComboBox(parent)
return editor
def setEditorData(self, editor, index):
model = index.model()
items = model.items
text = items[index.row()][index.column()]
editor.setCurrentText(text)
def setModelData(self, editor, model, index):
items = model.items
#
class TableView(QtWidgets.QTableView):
def __init__(self, parent=None):
super(TableView, self).__init__(parent=None)
delegate = Delegate()
self.setItemDelegate(delegate)
#Here is the crash point
# self.setItemDelegateForColumn(6, delegate)
# self.setItemDelegateForColumn(11, IconDelegate())
self.tableModel = TableModel(2, 15)
self.setModel(self.tableModel)
def keyPressEvent(self, event):
if event.key() == QtCore.Qt.Key_1:
self.tableModel.insertRows(0)
class TableItem(object):
def __init__(self, parent=None):
self.root = False
self.word = ""
self.alignment = QtCore.Qt.AlignCenter
self.rule = ""
self.foregroundcolor = QtGui.QColor(QtCore.Qt.black)
self.backgroundcolor = QtGui.QColor(QtCore.Qt.white)
self.font = QtGui.QFont("Meiryo", 14)
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, row = 0, column = 0, parent = None):
super(TableModel, self).__init__(parent = None)
self.items = [[TableItem() for c in range(column)] for r in range(row)]
self.root = QtCore.QModelIndex()
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.items)
def columnCount(self, parent=QtCore.QModelIndex()):
return 15
def data(self, index, role = QtCore.Qt.DisplayRole):
if not index.isValid():
return None
row = index.row()
column = index.column()
if role == QtCore.Qt.DisplayRole:
item = self.items[row][column]
return item
def headerData(self, section, orientation, role = QtCore.Qt.DisplayRole):
if orientation == QtCore.Qt.Orientation.Horizontal:
if role == QtCore.Qt.DisplayRole:
return alphabet[section]
return super(TableModel, self).headerData(section, orientation, role)
def flags(self, index):
return QtCore.Qt.ItemFlag.ItemIsEditable|QtCore.Qt.ItemFlag.ItemIsEnabled|QtCore.Qt.ItemFlag.ItemIsSelectable
def setData(self, index, value, role=QtCore.Qt.EditRole):
if role == QtCore.Qt.EditRole:
row, column = index.row(), index.column()
self.items[row][column] = value
self.dataChanged.emit(index, index)
return True
elif role == QtCore.Qt.DisplayRole:
row, column = index.row(), index.column()
self.items[row][column] = value
self.dataChanged.emit(index, index)
return True
elif role == QtCore.Qt.FontRole:
string = value.toString()
s = string.split(",")
font = s[0]
self.dataChanged.emit(index, index)
return True
def insertRows(self, position, rows=1, index=QtCore.QModelIndex()):
self.beginInsertRows(QtCore.QModelIndex(), position, position+rows-1)
for row in range(rows):
self.items.insert(position+row, [TableItem() for c in range(self.columnCount())])
self.endInsertRows()
self.emit(QtCore.SIGNAL("dataChanged(QModelIndex, QModelIndex)"), index, index)
self.emit(QtCore.SIGNAL("layoutChanged()"))
return True
def removeRows(self, position, rows=1, index=QtCore.QModelIndex()):
self.beginRemoveRows(QtCore.QModelIndex(), position, position+rows-1)
for row in range(rows):
self.items = self.items[:position] + \
self.items[position + rows:]
self.emit(QtCore.SIGNAL("dataChanged(QModelIndex, QModelIndex)"), index, index)
self.emit(QtCore.SIGNAL("layoutChanged()"))
return True
def main():
if QtWidgets.QApplication.instance() is not None:
app = QtWidgets.QApplication.instance()
else:
app = QtWidgets.QApplication([])
mainwindow = TableView()
mainwindow.show()
sys.exit(QtWidgets.QApplication.exec_())
if __name__ == "__main__":
main()
这不是Qt的bug,而是你自己代码的bug。
首先建议你从CMD控制台运行你的代码,这样你就可以得到错误信息,如果你这样做,你会看到错误信息是。
Traceback (most recent call last):
File "main.py", line 38, in setEditorData
editor.setCurrentText(text)
TypeError: 'PySide2.QtWidgets.QComboBox.setCurrentText' called with wrong argument types:
PySide2.QtWidgets.QComboBox.setCurrentText(TableItem)
Supported signatures:
PySide2.QtWidgets.QComboBox.setCurrentText(str)
该错误清楚地表明setCurrentText方法期望的是一个字符串 但却收到一个TableItem. 为什么你会收到一个TableItem?你的代码是这样的 items[index.row()][index.column()]
返回一个TableItem,假设你想得到文本 "word",那么你必须使用。
def setEditorData(self, editor, index):
model = index.model()
items = model.items
item = items[index.row()][index.column()]
text = item.word
editor.setCurrentText(text)
在这两种情况下(setItemDelegate或setItemD)都会导致错误。
但是当调整窗口大小时,错误仍然存在,因为它是由其他委托人引起的。由于你部分覆盖了一个委托人,那么对方继续使用通用信息,例如期望 index.data(Qt.DisplayRole)
来返回一个字符串,但在你的例子中则返回一个TableItem。
def data(self, index, role = QtCore.Qt.DisplayRole):
if not index.isValid():
return None
row = index.row()
column = index.column()
if role == QtCore.Qt.DisplayRole:
item = self.items[row][column]
return item
总之,OP没有正确使用默认的角色,导致使用这些信息的委托人获得错误的数据。
考虑到以上种种,我纠正了很多之前没有提到的错误,因为很多错误都是琐碎的,或者是不符合题意的,得到以下代码。
from PySide2 import QtWidgets
from PySide2 import QtCore
from PySide2 import QtGui
from PySide2 import QtSql
import os
import PySide2
import sys
dirname = os.path.dirname(PySide2.__file__)
plugin_path = os.path.join(dirname, "plugins", "platforms")
os.environ["QT_QPA_PLATFORM_PLUGIN_PATH"] = plugin_path
alphabet = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O"]
class IconDelegate(QtWidgets.QStyledItemDelegate):
def initStyleOption(self, option, index):
super(IconDelegate, self).initStyleOption(option, index)
if option.features & QtWidgets.QStyleOptionViewItem.HasDecoration:
s = option.decorationSize
s.setWidth(option.rect.width())
option.decorationSize = s
class Delegate(QtWidgets.QStyledItemDelegate):
def initStyleOption(self, option, index):
if option.features & QtWidgets.QStyleOptionViewItem.HasDecoration:
s = option.decorationSize
s.setWidth(option.rect.width())
option.decorationSize = s
def createEditor(self, parent, option, index):
editor = QtWidgets.QComboBox(parent)
return editor
#
class TableView(QtWidgets.QTableView):
def __init__(self, parent=None):
super(TableView, self).__init__(parent=None)
delegate = Delegate(self)
# self.setItemDelegate(delegate)
# Here is the crash point
self.setItemDelegateForColumn(6, delegate)
icon_delegate = IconDelegate(self)
self.setItemDelegateForColumn(11, icon_delegate)
self.tableModel = TableModel(2, 15)
self.setModel(self.tableModel)
def keyPressEvent(self, event):
if event.key() == QtCore.Qt.Key_1:
self.tableModel.insertRows(0)
class TableItem(object):
def __init__(self, parent=None):
self.root = False
self.word = ""
self.alignment = QtCore.Qt.AlignCenter
self.rule = ""
self.foregroundcolor = QtGui.QColor(QtCore.Qt.black)
self.backgroundcolor = QtGui.QColor(QtCore.Qt.white)
self.font = QtGui.QFont("Meiryo", 14)
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, row=0, column=0, parent=None):
super(TableModel, self).__init__(parent=None)
self.items = [[TableItem() for c in range(column)] for r in range(row)]
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.items)
def columnCount(self, parent=QtCore.QModelIndex()):
if self.items:
return len(self.items[0])
return 0
def data(self, index, role=QtCore.Qt.DisplayRole):
if not index.isValid():
return None
row = index.row()
column = index.column()
if 0 <= row < self.rowCount() and 0 <= column < self.columnCount():
item = self.items[row][column]
if role == QtCore.Qt.DisplayRole:
text = item.word
return text
elif role == QtCore.Qt.EditRole:
return item
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
if orientation == QtCore.Qt.Orientation.Horizontal:
if role == QtCore.Qt.DisplayRole and section < len(alphabet):
return alphabet[section]
return super(TableModel, self).headerData(section, orientation, role)
def flags(self, index):
return (
QtCore.Qt.ItemFlag.ItemIsEditable
| QtCore.Qt.ItemFlag.ItemIsEnabled
| QtCore.Qt.ItemFlag.ItemIsSelectable
)
def setData(self, index, value, role=QtCore.Qt.EditRole):
if role == QtCore.Qt.EditRole:
row, column = index.row(), index.column()
self.items[row][column].word = value
self.dataChanged.emit(index, index)
return True
elif role == QtCore.Qt.DisplayRole:
row, column = index.row(), index.column()
self.items[row][column].word = value
self.dataChanged.emit(index, index)
return True
return False
def insertRows(self, position, rows=1, index=QtCore.QModelIndex()):
self.beginInsertRows(QtCore.QModelIndex(), position, position + rows - 1)
for row in range(rows):
self.items.insert(
position + row, [TableItem() for c in range(self.columnCount())]
)
self.endInsertRows()
self.emit(QtCore.SIGNAL("dataChanged(QModelIndex, QModelIndex)"), index, index)
self.emit(QtCore.SIGNAL("layoutChanged()"))
return True
def removeRows(self, position, rows=1, index=QtCore.QModelIndex()):
self.beginRemoveRows(QtCore.QModelIndex(), position, position + rows - 1)
for row in range(rows):
self.items = self.items[:position] + self.items[position + rows :]
self.emit(QtCore.SIGNAL("dataChanged(QModelIndex, QModelIndex)"), index, index)
self.emit(QtCore.SIGNAL("layoutChanged()"))
return True
def main():
if QtWidgets.QApplication.instance() is not None:
app = QtWidgets.QApplication.instance()
else:
app = QtWidgets.QApplication([])
mainwindow = TableView()
mainwindow.show()
sys.exit(QtWidgets.QApplication.exec_())
if __name__ == "__main__":
main()