无法从 QtGui.QStandardItem 发出信号
Unable to emit signal from QtGui.QStandardItem
我正在尝试覆盖 QTreeView
来处理调整 parents 和 children(如果复选框被修改)。但是我无法发出信号,我不确定是不是因为我正在尝试继承 QtGui
而不是 QtWidgets
.
这是将触发错误的代码:
class QStandardItem(QtGui.QStandardItem):
someSignal = QtCore.Signal()
def __init__(self, *args, **kwargs):
QtGui.QStandardItem.__init__(self, *args, **kwargs)
self.someSignal.emit()
>>> QStandardItem()
# AttributeError: 'PySide2.QtCore.Signal' object has no attribute 'emit' #
这是我目前的代码,仅供参考:
class QStandardItem(QtGui.QStandardItem):
checkStateChanged = QtCore.Signal(object)
def __init__(self, *args, **kwargs):
QtGui.QStandardItem.__init__(self, *args, **kwargs)
def setData(self, data, role):
if role == QtCore.Qt.CheckStateRole:
self.checkStateChanged.emit(self)
QtGui.QStandardItem.setData(self, data, role)
class QTreeView(QtWidgets.QTreeView):
def __init__(self, *args, **kwargs):
QtWidgets.QTreeView.__init__(self, *args, **kwargs)
#I need to know when to trigger this as it edits other nodes
def checkStateChanged(self, model_index):
selected_item = self.model().itemFromIndex(model_index)
check_state = selected_item.checkState()
#Handle child nodes
for i in range(selected_item.rowCount()):
child_item = selected_item.child(i)
if child_item.isCheckable():
child_item.setCheckState(check_state)
#Handle parent nodes
parent_item = selected_item.parent()
check_states = {QtCore.Qt.Checked: 0,
QtCore.Qt.PartiallyChecked: 1,
QtCore.Qt.Unchecked: 2}
counts = [0, 0, 0]
if parent_item is not None:
for i in range(parent_item.rowCount()):
child_item = parent_item.child(i)
if child_item.isCheckable():
counts[check_states[child_item.checkState()]] += 1
if counts[0] and not counts[1] and not counts[2]:
parent_item.setCheckState(QtCore.Qt.Checked)
elif not counts[0] and not counts[1] and counts[2]:
parent_item.setCheckState(QtCore.Qt.Unchecked)
else:
parent_item.setCheckState(QtCore.Qt.PartiallyChecked)
不是 100% 确定,但对于 Python 为了定义您自己的信号,您必须使用:
QtCore.pyqtSignal()
此外,您可能还需要继承 QtCore.QObject
才能使用信号
编辑:刚看到你在使用 pyside,所以放弃了第一个解决方案,但继承 QObject 是你的解决方案
正如您所指出的,只有从 QObject
继承的 类 可以发出信号,QStandardItem
不是 QObject
,因此会产生该问题。适当的选择是使用 QStandardItemModel,为此我们覆盖 setData()
方法并建立逻辑来验证状态是否已更改,然后使用 itemFromIndex()
方法发出 QStandardItem
returns 一个 QStandardItem
给定一个 QModelIndex
.
示例:
from PySide2 import QtCore, QtGui, QtWidgets
class StandardItemModel(QtGui.QStandardItemModel):
checkStateChanged = QtCore.Signal(QtGui.QStandardItem)
def setData(self, index, value, role=QtCore.Qt.EditRole):
if role == QtCore.Qt.CheckStateRole:
last_value = self.data(index, role)
val = super(StandardItemModel, self).setData(index, value, role)
if role == QtCore.Qt.CheckStateRole and val:
current_value = self.data(index, role)
if last_value != current_value:
it = self.itemFromIndex(index)
self.checkStateChanged.emit(it)
return val
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
w = QtWidgets.QTreeView()
model = StandardItemModel(w)
w.setModel(model)
model.checkStateChanged.connect(self.foo_slot)
for i in range(4):
top_level = QtGui.QStandardItem("{}".format(i))
top_level.setCheckable(True)
model.appendRow(top_level)
for j in range(5):
it = QtGui.QStandardItem("{}-{}".format(i, j))
it.setCheckable(True)
top_level.appendRow(it)
w.expandAll()
self.setCentralWidget(w)
@QtCore.Slot(QtGui.QStandardItem)
def foo_slot(self, item):
print(item.text(), item.checkState())
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
我正在尝试覆盖 QTreeView
来处理调整 parents 和 children(如果复选框被修改)。但是我无法发出信号,我不确定是不是因为我正在尝试继承 QtGui
而不是 QtWidgets
.
这是将触发错误的代码:
class QStandardItem(QtGui.QStandardItem):
someSignal = QtCore.Signal()
def __init__(self, *args, **kwargs):
QtGui.QStandardItem.__init__(self, *args, **kwargs)
self.someSignal.emit()
>>> QStandardItem()
# AttributeError: 'PySide2.QtCore.Signal' object has no attribute 'emit' #
这是我目前的代码,仅供参考:
class QStandardItem(QtGui.QStandardItem):
checkStateChanged = QtCore.Signal(object)
def __init__(self, *args, **kwargs):
QtGui.QStandardItem.__init__(self, *args, **kwargs)
def setData(self, data, role):
if role == QtCore.Qt.CheckStateRole:
self.checkStateChanged.emit(self)
QtGui.QStandardItem.setData(self, data, role)
class QTreeView(QtWidgets.QTreeView):
def __init__(self, *args, **kwargs):
QtWidgets.QTreeView.__init__(self, *args, **kwargs)
#I need to know when to trigger this as it edits other nodes
def checkStateChanged(self, model_index):
selected_item = self.model().itemFromIndex(model_index)
check_state = selected_item.checkState()
#Handle child nodes
for i in range(selected_item.rowCount()):
child_item = selected_item.child(i)
if child_item.isCheckable():
child_item.setCheckState(check_state)
#Handle parent nodes
parent_item = selected_item.parent()
check_states = {QtCore.Qt.Checked: 0,
QtCore.Qt.PartiallyChecked: 1,
QtCore.Qt.Unchecked: 2}
counts = [0, 0, 0]
if parent_item is not None:
for i in range(parent_item.rowCount()):
child_item = parent_item.child(i)
if child_item.isCheckable():
counts[check_states[child_item.checkState()]] += 1
if counts[0] and not counts[1] and not counts[2]:
parent_item.setCheckState(QtCore.Qt.Checked)
elif not counts[0] and not counts[1] and counts[2]:
parent_item.setCheckState(QtCore.Qt.Unchecked)
else:
parent_item.setCheckState(QtCore.Qt.PartiallyChecked)
不是 100% 确定,但对于 Python 为了定义您自己的信号,您必须使用:
QtCore.pyqtSignal()
此外,您可能还需要继承 QtCore.QObject
才能使用信号
编辑:刚看到你在使用 pyside,所以放弃了第一个解决方案,但继承 QObject 是你的解决方案
正如您所指出的,只有从 QObject
继承的 类 可以发出信号,QStandardItem
不是 QObject
,因此会产生该问题。适当的选择是使用 QStandardItemModel,为此我们覆盖 setData()
方法并建立逻辑来验证状态是否已更改,然后使用 itemFromIndex()
方法发出 QStandardItem
returns 一个 QStandardItem
给定一个 QModelIndex
.
示例:
from PySide2 import QtCore, QtGui, QtWidgets
class StandardItemModel(QtGui.QStandardItemModel):
checkStateChanged = QtCore.Signal(QtGui.QStandardItem)
def setData(self, index, value, role=QtCore.Qt.EditRole):
if role == QtCore.Qt.CheckStateRole:
last_value = self.data(index, role)
val = super(StandardItemModel, self).setData(index, value, role)
if role == QtCore.Qt.CheckStateRole and val:
current_value = self.data(index, role)
if last_value != current_value:
it = self.itemFromIndex(index)
self.checkStateChanged.emit(it)
return val
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
w = QtWidgets.QTreeView()
model = StandardItemModel(w)
w.setModel(model)
model.checkStateChanged.connect(self.foo_slot)
for i in range(4):
top_level = QtGui.QStandardItem("{}".format(i))
top_level.setCheckable(True)
model.appendRow(top_level)
for j in range(5):
it = QtGui.QStandardItem("{}-{}".format(i, j))
it.setCheckable(True)
top_level.appendRow(it)
w.expandAll()
self.setCentralWidget(w)
@QtCore.Slot(QtGui.QStandardItem)
def foo_slot(self, item):
print(item.text(), item.checkState())
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())