qtquick/qml从pyqt5创建可扩展的子菜单
我想创建ListView,其中包含用于扩展和折叠子菜单的嵌套ListModel。 (在此处,我在。)。
我的问题是可扩展的菜单是在我创建Python/pyqt5的ListModel时没有响应的。但是,如果我在QML侧创建它,则扩展操作正常运行。 (但是我不想在qml侧创建它,因为我必须在后端进行操作。)
这是main.py
import sys
from PyQt5.QtQml import QQmlApplicationEngine, qmlRegisterType
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtCore import QTimer, QObject, pyqtSignal, pyqtSlot, QAbstractListModel, QModelIndex, Qt, pyqtProperty
class Backend(QObject):
modelChanged = pyqtSignal()
def __init__(self):
super().__init__()
self._model = MyListModel()
##~~Expose model as a property of our backend~~##
@pyqtProperty(QObject, constant=False, notify=modelChanged)
def model(self):
return self._model
class MyListModel(QAbstractListModel):
##~~My Custom UserRoles~~##
NameRole = Qt.UserRole + 1000
CollapsedRole = Qt.UserRole + 1001
SubItemsRole = Qt.UserRole + 1002
def __init__(self, parent=None):
super().__init__()
self.itemNames = []
def rowCount(self, parent=None, *args, **kwargs):
return len(self.itemNames)
def data(self, index, role=Qt.DisplayRole):
if 0 <= index.row() < self.rowCount() and index.isValid():
item = self.itemNames[index.row()]
if role == MyListModel.NameRole:
return item['assetName']
elif role == MyListModel.SubItemsRole:
return item['subItems']
elif role == MyListModel.CollapsedRole:
return item['isCollapsed']
def roleNames(self):
roles = dict()
roles[MyListModel.NameRole] = b'assetName'
roles[MyListModel.SubItemsRole] = b'subItems'
roles[MyListModel.CollapsedRole] = b'isCollapsed'
return roles
@pyqtSlot(str, bool)
def appendRow(self, name, isCollapsed):
self.subItem = MySubListModel()
self.subItem.addRow()
self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount())
self.itemNames.append({'assetName': name, 'subItems': self.subItem, 'isCollapsed': isCollapsed})
self.endInsertRows()
print(self.itemNames)
print(self.subItem.subItemParams)
@pyqtSlot(int, str)
def collapseEditInputsMenu(self, index, modelIndexName):
self.itemNames[index][modelIndexName] = not self.itemNames[index][modelIndexName]
print(f"From Backend: {self.itemNames}")
class MySubListModel(QAbstractListModel):
##~~My Custom UserRole For SubItem ListModel~~##
CellSizeRole = Qt.UserRole + 1004
def __init__(self, parent=None):
super().__init__()
self.subItemParams = []
def rowCount(self, parent=None, *args, **kwargs):
return len(self.subItemParams)
def data(self, index, role=Qt.DisplayRole):
if 0 <= index.row() < self.rowCount() and index.isValid():
item = self.subItemParams[index.row()]
if role == MySubListModel.CellSizeRole:
return item['cellSize']
def roleNames(self):
roles = dict()
roles[MySubListModel.CellSizeRole] = b'cellSize'
return roles
def addRow(self):
self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount())
self.subItemParams.append({'cellSize': "888"})
self.endInsertRows()
class MainWindow():
def __init__(self):
app = QGuiApplication(sys.argv)
self.engine = QQmlApplicationEngine()
self.engine.quit.connect(app.quit)
self.engine.load("main.qml")
app_backend = Backend()
self.engine.rootObjects()[0].setProperty("backendObjectInQML", app_backend)
sys.exit(app.exec())
def main():
window = MainWindow()
if __name__ == '__main__':
main()
...和main.qml
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtGraphicalEffects 1.15
ApplicationWindow {
id: myApplicationWindow
title: "Expandable ListView App"
visible: true
height: 400
width: 400
property QtObject backendObjectInQML
Rectangle {
id: rootRectangle
color: "grey"
anchors.fill: parent
Item {
id: solutionFileListViewRoot
anchors.fill: parent
// ListModel {
// id: myNestedListModel
// ListElement {
// assetName: "Dummy Item"
// isCollapsed: true
// subItems: [ListElement {cellSize: "888"}]
// }
// }
ListView {
id: myNestedListView
anchors {
top: parent.top
left: parent.left
right: parent.right
bottom: parent.bottom
bottomMargin: 50
}
model: myApplicationWindow.backendObjectInQML.model
// model: myNestedListModel
delegate: myAppListElementDelegate
spacing: 6
clip: true
ScrollBar.vertical: ScrollBar {
active: true
}
}
}
Component {
id: myAppListElementDelegate
Column {
id: listElementColumn
width: myNestedListView.width
Rectangle {
id: listElementRectangle
height: 30
anchors {
left: parent.left
right: parent.right
rightMargin: 15
leftMargin: 15
}
color: "yellow"
radius: 3
Text {
height: 24
width: 100
text: assetName
anchors {
verticalCenter: parent.verticalCenter
left: parent.left
}
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
color: "black"
}
Button {
id: expandButton
width: 70
height: 24
text: "Expand"
anchors {
right: parent.right
rightMargin: 20
verticalCenter: parent.verticalCenter
}
onClicked: {
myNestedListView.currentIndex = index
myApplicationWindow.backendObjectInQML.model.collapseEditInputsMenu(index, "isCollapsed")
// myNestedListModel.setProperty(index, "isCollapsed", !isCollapsed)
console.log("From QML isCollapsed:")
console.log(isCollapsed)
}
}
}
Loader {
id: subSolutionEditItemLoader
visible: !isCollapsed
property variant subEditItemModel: subItems
sourceComponent: isCollapsed ? null : subItemEditInputsDelegate
onStatusChanged: {
// console.log(subItems)
if(status == Loader.Ready) item.model = subEditItemModel
}
}
}
}
Component {
id: subItemEditInputsDelegate
Column {
property alias model: subItemRepeater.model
id: nestedListElementColumn
width: myNestedListView.width
anchors {
top: parent.top
topMargin: 3
}
spacing: 3
Repeater {
id: subItemRepeater
width: parent.width
delegate: Rectangle {
id: nestedListElementRectangle
color: "blue"
height: 40
anchors {
left: parent.left
leftMargin: 30
right: parent.right
rightMargin: 30
}
radius: 5
Rectangle {
id: cellSizeBackground
height: 20
width: cellSizeLabel.implicitWidth
color: "#00000000"
anchors {
left: parent.left
leftMargin: 25
top: parent.top
topMargin: 10
}
Label {
id: cellSizeLabel
text: "Cell Size: "
anchors.fill: parent
verticalAlignment: Text.AlignVCenter
color: "#6e95bc"
}
}
Rectangle {
id: cellSizeTextInputBorder
height: 24
width: 120
color: "#00000000"
radius: 5
anchors {
left: cellSizeBackground.right
leftMargin: 10
verticalCenter: cellSizeBackground.verticalCenter
}
border.width: 1
border.color: "#12C56A"
TextInput {
id: cellSizeTextInput
text: cellSize
verticalAlignment: Text.AlignVCenter
anchors.fill: parent
color: "#6e95bc"
selectByMouse: true
leftPadding: 5
rightPadding: 5
clip: true
onEditingFinished: {
console.log("cellSizeTextInput edited...")
}
}
}
}
}
}
}
Button {
id: addListElementButton
height: 24
width: 70
text: "Add"
anchors {
bottom: parent.bottom
right: parent.right
}
onClicked: {
myApplicationWindow.backendObjectInQML.model.appendRow("Dummy Item", false)
}
}
}
}
。没错,它已在listView上进行更新,但以某种方式没有触发GUI。但是我不知道为什么。
我还为QML添加了嵌套的ListModel和相关行,如想要尝试使用QML端创建的ListModel的代码的人所注释的。
您可以在下面看到应用程序屏幕截图:
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您在更改倒塌状态时没有发出任何信号。
因此,无法理解该角色的财产可以知道它们需要与之同步。
更改:
到:
ps:这是非常混乱的代码,我在这里列出一些严重的错误:
第一:
这是多余的,您应该使用:
第二:
如果您将使用
context> context property
,如我所说的,您无需访问它,myApplicationWindow
third third:
iScollapsed
来自模型的角色可能是冗余的,您应该更喜欢为myAppListelementDelegate
component创建属性。这样的事情:
You didn't emitted any signals while changing the collapsed state.
Therefore there was no way for properties that relay on that role to know that they need to synchronize with it.
Change:
To:
Fully working example
P.S: This is very messy code, I'll list you here a few severe mistakes:
First:
This is redundant you should use instead:
Second:
If you will use
contextProperty
as I said above you don't need to access it threwmyApplicationWindow
Third:
The
isCollapsed
role from your model is probably redundant and you should have preferred creating a property for yourmyAppListElementDelegate
component.Something like this: