使用多个小部件进行委托
Posted
技术标签:
【中文标题】使用多个小部件进行委托【英文标题】:Delegate with multiple widgets 【发布时间】:2017-08-01 16:54:31 【问题描述】:基础模拟:
你好,
我有什么:
QAbstractListModel 包含我的项目。 QListView 将包含单个小部件或委托。 QListView 中的每个单独项目都需要在小部件中有 3 个可编辑区域。前言:
我无法弄清楚如何让适当的分层小部件系统正常工作。如果您查看附加的图像,每个绿色框代表我模型中的一个“项目”,以及在我看来用户的一个单独项目,而每个绿色框内的“小部件”上的数据是来自并与模型中的该项目相关。
因此,如果有人在 Widget 1 中编辑 QLineEdit1,我希望模型中的数据将更新 Widget1 相关的项目。
问题:
我不知道如何让多个编辑器在同一个委托中工作。如果我点击项目(QLineEdit),索引当然会与主要的小部件项目(绿色框)相关 - 我找不到任何东西告诉我我点击了绘制的 QLineEdit,所以如果我只是在 createEditor 中返回一个可编辑的 QLineEdit,它只是一个通用的,放置在任何地方,我需要弄清楚它与哪个小部件相关,以便我可以正确更新模型,还可以让编辑器绘制我点击绘制的 QLineEdit 的位置。
我不知道如何让一个好的系统正常工作。我了解代表,我了解 MVC,这一切都很好。我只是不知道我正在尝试做的事情是否可行,或者我需要改变它并做其他事情。如果我确实需要尝试其他东西,我会很感激一些建议。
谢谢。
这里有一些基本代码(现在没有在小部件内绘制单个项目,但已经设置了基础):
import sys
from PySide import QtCore, QtGui
DELEGATE_DATA_ROLE = 37
DELEGATE_INDEX = 0
class ItemWidget(QtGui.QWidget):
def __init__(self, parent=None):
super(ItemWidget, self).__init__(parent=parent)
self.main_layout = QtGui.QVBoxLayout()
self.setLayout(self.main_layout)
class ItemDelegate(QtGui.QStyledItemDelegate):
def __init__(self, parent=None):
super(ItemDelegate, self).__init__(parent=parent)
def sizeHint(self, option, index):
return QtCore.QSize(80, 80)
def createEditor(self, parent, option, index):
editor = QtGui.QLineEdit(parent)
editor.setFixedWidth(200)
editor.setFixedHeight(50)
return editor
def setEditorData(self, editor, index):
item_str = index.data(QtCore.Qt.DisplayRole)
description = item_str['description']
editor.setValue(description)
def setEditorData(self, editor, index):
print 'running setEditorData'
if index.column() == DELEGATE_INDEX:
print 'delegate'
else:
QtGui.QStyledItemDelegate(self, editor, index)
class ItemModel(QtCore.QAbstractListModel):
def __init__(self, parent=None):
super(ItemModel, self).__init__(parent=parent)
self.items = [
'one': '1', 'name': 'one', 'thumbnail': 'charlie.jpg', 'description': 'aabb',
'two': '2', 'name': 'two', 'thumbnail': 'charlie.jpg', 'description': 'aabb',
'three': '3', 'name': 'three', 'thumbnail': 'charlie.jpg', 'description': 'aabb',
'four': '4', 'name': 'four', 'thumbnail': 'charlie.jpg', 'description': 'aabb',
'five': '5', 'name': 'five', 'thumbnail': 'charlie.jpg', 'description': 'aabb',
'six': '6', 'name': 'six', 'thumbnail': 'charlie.jpg', 'description': 'aabb'
]
def rowCount(self, index):
return len(self.items)
def data(self, index, role=QtCore.Qt.DisplayRole):
if not index.isValid():
return None
if role == QtCore.Qt.DisplayRole:
if 0 <= index.row() < self.rowCount(index):
return self.items[index.row()]
if role == DELEGATE_DATA_ROLE:
item = self.items[index.row()]
return item, item.get('name'), item.get('description'), item.get('thumbnail')
if role == QtCore.Qt.EditRole:
return self.items[index.row()]
def setData(self, index, value, role=QtCore.Qt.EditRole):
if role == QtCore.Qt.EditRole:
self.items[index.row()] = value
self.dataChanged.emit(index, index)
return True
return False
def flags(self, index):
flag = super(ItemModel, self).flags(index)
return flag | QtCore.Qt.ItemIsEditable
class ListView(QtGui.QListView):
def __init__(self, parent=None):
super(ListView, self).__init__(parent=parent)
class TestUI(QtGui.QDialog):
def __init__(self, parent=None):
super(TestUI, self).__init__(parent)
self.main_layout = QtGui.QVBoxLayout()
self.resize(700, 500)
self.view = ListView()
self.item_delegate = ItemDelegate()
self.view.setItemDelegate(self.item_delegate)
self.model = ItemModel()
self.view.setModel(self.model)
self.item_widget = ItemWidget()
self.setLayout(self.main_layout)
self.main_layout.addWidget(self.view)
self.main_layout.addWidget(self.item_widget)
def start():
app = QtGui.QApplication(sys.argv)
ui = TestUI()
ui.show()
ui.setWindowState(QtCore.Qt.WindowActive)
ui.raise_()
app.exec_()
if __name__ == '__main__':
start()
【问题讨论】:
你的模型适合你吗? 是的,我的模型工作正常 - 现在没有任何显示,直到您双击,因为这只是表明我无法弄清楚如何知道在委托中点击了什么。 在role == QtCore.Qt.DisplayRole
中你必须返回一个字符串,但你返回的是一个字典,这对我来说似乎很奇怪。
我得到以下信息:imgur.com/a/18XX6
再一次,里面什么都没有显示,这只是一个非常基本的视图,没有填充委托绘制的项目 - 随意在角色部分返回一个字符串,但这不是问题所在参考。
【参考方案1】:
您的代码仅定义编辑器 - 即 Qt 在编辑项目时显示的内容。您需要提供一个绘制方法,然后 Qt 调用该方法为每个项目绘制。
这是一个在项目的右边缘绘制一个三点按钮的示例(在 C++ 中):
void ColorDelegate::paint(
QPainter * a_Painter,
const QStyleOptionViewItem & a_Option,
const QModelIndex & a_Index
) const
// Draw the button:
QStyleOptionButton button;
button.rect = buttonRectFromItemRect(a_Option.rect);
button.text = "...";
button.state = QStyle::State_Enabled;
QApplication::style()->drawControl(QStyle::CE_PushButton, &button, a_Painter);
// Draw the text, using the original delegate:
QStyleOptionViewItem txt(a_Option);
txt.rect.setWidth(txt.rect.width() - txt.rect.height() - 1);
Super::paint(a_Painter, txt, a_Index);
(取自https://github.com/madmaxoft/SkauTan/blob/a40b94d8646c215ddde3efe422c466ca8b15cb88/src/UI/ColorDelegate.cpp#L20-L37)
【讨论】:
以上是关于使用多个小部件进行委托的主要内容,如果未能解决你的问题,请参考以下文章
如何在颤动的pageView中使用AnimatedCrossFade多个小部件?