菜单元素的 ListView 信号和槽

ListView signals and slots for menu elements

我正在尝试使用自定义元素实现某种自定义菜单。最终目标是创建某种带有文本和图标的弹出菜单。但是在创作过程中我遇到了一些问题。我可以展示 2 个主要问题:

  1. 第一个位置有一个标题为 Hello world 的奇怪菜单元素(看起来是阅读应用程序 window 的标题):

  1. 有时我会收到类似 qrc:/BreezeQuickMenu.qml:45: TypeError: Property 'clicked' of object QQuickListView(0x1120830) is not a function
  2. 的错误

这是我的实际代码:

main.qml

import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Window 2.2

ApplicationWindow {
    title: qsTr("Hello World")
    width: Screen.width
    height: Screen.height
    visible: true
    id: win
    color: brPalette.normalBackground
BreezeQuickMenu{
    id: brMenu
    x: 490
    y: 199
    width: 128
    height: 256
    palette: brPalette
    menuFont.pointSize: 16
    BreezeQuickMenuItem{
        title: "Item 1"
        onClicked: mbox.show()
    }
    BreezeQuickMenuItem{
        title: "Item 2"
    }
    BreezeQuickMenuItem{
        title: "Item 3"
    }
  }
}

BreezeQuickMenu.qml

import QtQuick 2.4

Item {
    id: root
    property BreezeQuickPalette palette: BreezeQuickPalette
    property alias currentIndex: menuList.currentIndex
    property font menuFont
    property bool menuVisible: false
    implicitWidth: 128
    implicitHeight: menuList.height
    ListView{
        id: menuList
        anchors.fill: parent
        model: root.children
        clip: true
        delegate: Component {
            id: menuItem
            Rectangle {
                id: menuElement
                property bool isCurrentItem: ListView.isCurrentItem
                anchors {
                    left: parent.left
                    right: parent.right
                }
                color: palette.normalBackground
                height: menuText.font.pixelSize*1.2
                Text {
                    id: menuText
                    anchors.fill: parent
                    text: title
                    color: palette.normalText
                    font: menuFont
                }
                MouseArea {
                    anchors.fill: parent
                    hoverEnabled: true
                    onClicked: {
                        menuList.currentIndex = index
                        menuList.model[index].clicked()
                    }
                }
            }
        }
    }
}

BreezeQuickMenuItem.qml

import QtQuick 2.4

Item {
    id: root
    property string title: "Menu Element"
    signal clicked
}

如您所见,我正在尝试使用它们自己的信号来实现菜单列表和菜单项。我有 2 个问题:

请帮助我理解。完整的项目可以在这里拉取:

git clone git://git.code.sf.net/p/breezequick/code breezequick-code

signal 的问题与其声明有关。信号总是被声明为函数:带有签名。换句话说,没有参数的 signal 的形式是

signal <signal_name>()

这也是您收到错误“is not a function”的原因。除此之外, signals/signal 处理程序的用法是正确的。无论如何,仔细阅读文档不会有什么坏处。 This page 详细介绍了论点。

谈到另一个问题,您做出了错误的假设:在组件 内声明的任何内容都是组件本身 children 部分。在这里你声明了一个 BreezeQuickMenu 它有一个 child ListView。当您使用它并添加 BreezeQuickMenuItem 时,您将它们添加到 ListView 所属的 相同的 集中。最后,children 属性 中有 四个 个元素。此外,通过 modelListView 添加到 自身 中,你会把事情搞得一团糟,以至于呈现完全不相关的字符串。

有几种方法可以将 Items 处理为视图的模型成员,包括 VisualItemModel and using object Instanced as models。但是,通过浏览您的代码,很明显您想要定义一个以声明方式添加菜单项的组件。在这种情况下使用 children 是不够的。您还需要 default 属性:

An object definition can have a single default property. A default property is the property to which a value is assigned if an object is declared within another object's definition without declaring it as a value for a particular property.

因此您可以为您的 BreezeQuickMenu 定义 default 属性 并利用它为您的列表获得所需的 children。一种常见的方法如下(代码简化):

import QtQuick 2.4

Item {
    id: root
    property BreezeQuickPalette palette: BreezeQuickPalette
    property alias currentIndex: menuList.currentIndex

    // default declaration  (1)
    default property alias contents: addItem.children

    // Item to which the inner declared meantime will belong  (2)
    Item {
        id: addItem
    }

    property font menuFont
    property bool menuVisible: false

    implicitWidth: 128
    implicitHeight: menuList.height
    ListView{
        id: menuList
        anchors.fill: parent
        model: contents                 // usage of the default property  (3)
        clip: true
        delegate: Rectangle {
            // your current delegate code
        }
    }
}

基本思想也是利用 property alias:基本上在 (1) 中我们说“在 BreezeQuickMenu 中声明的所有 Item 都自动 children addItem 的内部声明 Item (2)。通过这种方式,ListView 保持分开,而所有 BreezeQuickMenuItem 聚集在一起,在 addItemchildren 属性. 此时,对 ListViewmodel (3) 使用相同的 children 属性 就足够了就是这样。