从 QAction 触发器访问委托 class
Access delegate class from QAction Trigger
我有一个 QListWidget,它对项目及其子项目进行分类(它们都是可检查的)。
目前,虽然 checking/unchecking 类别项目适用于子项目,但我在上下文菜单中引入了该选项,其中该选项的工作方式与您选中和取消选中类别项目的方式相同。
但是在我的 update_opts
- 上下文菜单中的 QAction 中,虽然它确实允许我 check/uncheck 类别项目,但它不会影响子项目的检查状态。
此外,QListWidgetItem
似乎没有 trigger
或 toggle
信号,我可以利用它来触发委托 [=27= 中的 editorEvent
].
IsCategoryRole = QtCore.Qt.UserRole
ParentRole = QtCore.Qt.UserRole + 1
class CategoryDelegate(QtGui.QStyledItemDelegate):
def editorEvent(self, event, model, option, index):
old_state = model.data(index, QtCore.Qt.CheckStateRole)
res = super(CategoryDelegate, self).editorEvent(
event, model, option, index
)
current_state = model.data(index, QtCore.Qt.CheckStateRole)
if old_state != current_state:
if index.data(IsCategoryRole):
pix = QtCore.QPersistentModelIndex(index)
for i in range(model.rowCount()):
ix = model.index(i, 0)
if pix == ix.data(ParentRole):
model.setData(
ix, current_state, QtCore.Qt.CheckStateRole
)
return res
class ListWidget(QtGui.QListWidget):
def __init__(self, parent=None):
super(ListWidget, self).__init__(parent)
delegate = CategoryDelegate(self)
self.setItemDelegate(delegate)
def addCategory(self, text):
item = ListWidget.create_checkable_item(text)
item.setData(IsCategoryRole, True)
self.addItem(item)
return item
def addItemToCategory(self, category_item, text):
item = ListWidget.create_checkable_item(text)
item.setData(IsCategoryRole, False)
ix = self.indexFromItem(category_item)
pix = QtCore.QPersistentModelIndex(ix)
item.setData(ParentRole, pix)
self.addItem(item)
return item
@staticmethod
def create_checkable_item(text):
item = QtGui.QListWidgetItem(text)
item.setFlags(
item.flags()
| QtCore.Qt.ItemIsUserCheckable
| QtCore.Qt.ItemIsEditable
)
item.setCheckState(QtCore.Qt.Unchecked)
return item
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.RightButton:
list_menu = QtGui.QMenu(self)
selected_item = self.currentItem()
if selected_item.data(IsCategoryRole):
update_cat_items = QtGui.QAction("Check all or none", self)
update_cat_items.triggered.connect(self.update_opts)
list_menu.addAction(update_cat_items)
list_menu.exec_(QtGui.QCursor().pos())
else:
super(ListWidget, self).mousePressEvent(event)
def update_opts(self):
selected_item = self.currentItem()
state = selected_item.checkState() # It returns eith 0 or 2, instead of QtCore.Qt.Unchecked or QtCore.Qt.Checked
if state == QtCore.Qt.Checked:
# If opt is checked in the first place, set it to uncheck
selected_item.setCheckState(QtCore.Qt.Unchecked)
else:
# If opt is unchecked in the first place, set it to check
selected_item.setCheckState(QtCore.Qt.Checked)
class TestDialog(QtGui.QDialog):
def __init__(self, parent=None):
super(TestDialog, self).__init__()
self.listWidget = ListWidget()
all_num = self.listWidget.addCategory("-- All Nums --")
num_items = ["One", "Two", "Three"]
for num in num_items:
self.listWidget.addItemToCategory(all_num, num)
all_letters = self.listWidget.addCategory("-- All Letters --")
letter_items = ["A", "B", "C"]
for letter in letter_items:
self.listWidget.addItemToCategory(all_letters, letter)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.listWidget)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
w = TestDialog()
w.show()
sys.exit(app.exec_())
在我的 中,考虑到 OP 只希望只有在用户按下复选框时才允许行为,现在使用新方法将扩展行为,为此不需要委托,但创建一个自定义 QListWidgetItem,其中该方法被覆盖 setData() 方法:
from PyQt4 import QtCore, QtGui
IsCategoryRole = QtCore.Qt.UserRole
ParentRole = QtCore.Qt.UserRole + 1
class ListWidgetItem(QtGui.QListWidgetItem):
def setData(self, role, value):
if role == QtCore.Qt.CheckStateRole and self.data(IsCategoryRole):
lw = self.listWidget()
index = lw.indexFromItem(self)
pix = QtCore.QPersistentModelIndex(index)
for r in range(lw.count()):
print(r)
it = lw.item(r)
if pix == it.data(ParentRole):
it.setData(role, value)
super(ListWidgetItem, self).setData(role, value)
class ListWidget(QtGui.QListWidget):
def addCategory(self, text):
item = ListWidget.create_checkable_item(text)
item.setData(IsCategoryRole, True)
self.addItem(item)
return item
def addItemToCategory(self, category_item, text):
item = ListWidget.create_checkable_item(text)
item.setData(IsCategoryRole, False)
ix = self.indexFromItem(category_item)
pix = QtCore.QPersistentModelIndex(ix)
item.setData(ParentRole, pix)
self.addItem(item)
return item
@staticmethod
def create_checkable_item(text):
item = ListWidgetItem(text)
item.setFlags(
item.flags()
| QtCore.Qt.ItemIsUserCheckable
| QtCore.Qt.ItemIsEditable
)
item.setCheckState(QtCore.Qt.Unchecked)
return item
def contextMenuEvent(self, event):
list_menu = QtGui.QMenu()
it = self.itemAt(self.viewport().mapFromGlobal(QtGui.QCursor().pos()))
if it.data(IsCategoryRole):
update_cat_items = QtGui.QAction("Check all or none", self)
update_cat_items.triggered.connect(self.update_opts)
list_menu.addAction(update_cat_items)
list_menu.exec_(QtGui.QCursor().pos())
def update_opts(self):
it = self.itemAt(self.viewport().mapFromGlobal(QtGui.QCursor().pos()))
it.setCheckState(
QtCore.Qt.Unchecked
if it.checkState() == QtCore.Qt.Checked
else QtCore.Qt.Checked
)
class TestDialog(QtGui.QDialog):
def __init__(self, parent=None):
super(TestDialog, self).__init__()
self.listWidget = ListWidget()
all_num = self.listWidget.addCategory("-- All Nums --")
num_items = ["One", "Two", "Three"]
for num in num_items:
self.listWidget.addItemToCategory(all_num, num)
all_letters = self.listWidget.addCategory("-- All Letters --")
letter_items = ["A", "B", "C"]
for letter in letter_items:
self.listWidget.addItemToCategory(all_letters, letter)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.listWidget)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
w = TestDialog()
w.show()
sys.exit(app.exec_())
我有一个 QListWidget,它对项目及其子项目进行分类(它们都是可检查的)。
目前,虽然 checking/unchecking 类别项目适用于子项目,但我在上下文菜单中引入了该选项,其中该选项的工作方式与您选中和取消选中类别项目的方式相同。
但是在我的 update_opts
- 上下文菜单中的 QAction 中,虽然它确实允许我 check/uncheck 类别项目,但它不会影响子项目的检查状态。
此外,QListWidgetItem
似乎没有 trigger
或 toggle
信号,我可以利用它来触发委托 [=27= 中的 editorEvent
].
IsCategoryRole = QtCore.Qt.UserRole
ParentRole = QtCore.Qt.UserRole + 1
class CategoryDelegate(QtGui.QStyledItemDelegate):
def editorEvent(self, event, model, option, index):
old_state = model.data(index, QtCore.Qt.CheckStateRole)
res = super(CategoryDelegate, self).editorEvent(
event, model, option, index
)
current_state = model.data(index, QtCore.Qt.CheckStateRole)
if old_state != current_state:
if index.data(IsCategoryRole):
pix = QtCore.QPersistentModelIndex(index)
for i in range(model.rowCount()):
ix = model.index(i, 0)
if pix == ix.data(ParentRole):
model.setData(
ix, current_state, QtCore.Qt.CheckStateRole
)
return res
class ListWidget(QtGui.QListWidget):
def __init__(self, parent=None):
super(ListWidget, self).__init__(parent)
delegate = CategoryDelegate(self)
self.setItemDelegate(delegate)
def addCategory(self, text):
item = ListWidget.create_checkable_item(text)
item.setData(IsCategoryRole, True)
self.addItem(item)
return item
def addItemToCategory(self, category_item, text):
item = ListWidget.create_checkable_item(text)
item.setData(IsCategoryRole, False)
ix = self.indexFromItem(category_item)
pix = QtCore.QPersistentModelIndex(ix)
item.setData(ParentRole, pix)
self.addItem(item)
return item
@staticmethod
def create_checkable_item(text):
item = QtGui.QListWidgetItem(text)
item.setFlags(
item.flags()
| QtCore.Qt.ItemIsUserCheckable
| QtCore.Qt.ItemIsEditable
)
item.setCheckState(QtCore.Qt.Unchecked)
return item
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.RightButton:
list_menu = QtGui.QMenu(self)
selected_item = self.currentItem()
if selected_item.data(IsCategoryRole):
update_cat_items = QtGui.QAction("Check all or none", self)
update_cat_items.triggered.connect(self.update_opts)
list_menu.addAction(update_cat_items)
list_menu.exec_(QtGui.QCursor().pos())
else:
super(ListWidget, self).mousePressEvent(event)
def update_opts(self):
selected_item = self.currentItem()
state = selected_item.checkState() # It returns eith 0 or 2, instead of QtCore.Qt.Unchecked or QtCore.Qt.Checked
if state == QtCore.Qt.Checked:
# If opt is checked in the first place, set it to uncheck
selected_item.setCheckState(QtCore.Qt.Unchecked)
else:
# If opt is unchecked in the first place, set it to check
selected_item.setCheckState(QtCore.Qt.Checked)
class TestDialog(QtGui.QDialog):
def __init__(self, parent=None):
super(TestDialog, self).__init__()
self.listWidget = ListWidget()
all_num = self.listWidget.addCategory("-- All Nums --")
num_items = ["One", "Two", "Three"]
for num in num_items:
self.listWidget.addItemToCategory(all_num, num)
all_letters = self.listWidget.addCategory("-- All Letters --")
letter_items = ["A", "B", "C"]
for letter in letter_items:
self.listWidget.addItemToCategory(all_letters, letter)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.listWidget)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
w = TestDialog()
w.show()
sys.exit(app.exec_())
在我的
from PyQt4 import QtCore, QtGui
IsCategoryRole = QtCore.Qt.UserRole
ParentRole = QtCore.Qt.UserRole + 1
class ListWidgetItem(QtGui.QListWidgetItem):
def setData(self, role, value):
if role == QtCore.Qt.CheckStateRole and self.data(IsCategoryRole):
lw = self.listWidget()
index = lw.indexFromItem(self)
pix = QtCore.QPersistentModelIndex(index)
for r in range(lw.count()):
print(r)
it = lw.item(r)
if pix == it.data(ParentRole):
it.setData(role, value)
super(ListWidgetItem, self).setData(role, value)
class ListWidget(QtGui.QListWidget):
def addCategory(self, text):
item = ListWidget.create_checkable_item(text)
item.setData(IsCategoryRole, True)
self.addItem(item)
return item
def addItemToCategory(self, category_item, text):
item = ListWidget.create_checkable_item(text)
item.setData(IsCategoryRole, False)
ix = self.indexFromItem(category_item)
pix = QtCore.QPersistentModelIndex(ix)
item.setData(ParentRole, pix)
self.addItem(item)
return item
@staticmethod
def create_checkable_item(text):
item = ListWidgetItem(text)
item.setFlags(
item.flags()
| QtCore.Qt.ItemIsUserCheckable
| QtCore.Qt.ItemIsEditable
)
item.setCheckState(QtCore.Qt.Unchecked)
return item
def contextMenuEvent(self, event):
list_menu = QtGui.QMenu()
it = self.itemAt(self.viewport().mapFromGlobal(QtGui.QCursor().pos()))
if it.data(IsCategoryRole):
update_cat_items = QtGui.QAction("Check all or none", self)
update_cat_items.triggered.connect(self.update_opts)
list_menu.addAction(update_cat_items)
list_menu.exec_(QtGui.QCursor().pos())
def update_opts(self):
it = self.itemAt(self.viewport().mapFromGlobal(QtGui.QCursor().pos()))
it.setCheckState(
QtCore.Qt.Unchecked
if it.checkState() == QtCore.Qt.Checked
else QtCore.Qt.Checked
)
class TestDialog(QtGui.QDialog):
def __init__(self, parent=None):
super(TestDialog, self).__init__()
self.listWidget = ListWidget()
all_num = self.listWidget.addCategory("-- All Nums --")
num_items = ["One", "Two", "Three"]
for num in num_items:
self.listWidget.addItemToCategory(all_num, num)
all_letters = self.listWidget.addCategory("-- All Letters --")
letter_items = ["A", "B", "C"]
for letter in letter_items:
self.listWidget.addItemToCategory(all_letters, letter)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.listWidget)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
w = TestDialog()
w.show()
sys.exit(app.exec_())