【问题标题】:ListView signals and slots for menu elements菜单元素的 ListView 信号和槽
【发布时间】:2015-06-30 10:37:09
【问题描述】:

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

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

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

这是我的实际代码:

ma​​in.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
}

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

  • 如何正确摆脱使用父元素的title属性,因为我需要读取children的title属性

  • 在菜单元素中使用信号和槽以避免上述错误的正确方法是什么?

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

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

【问题讨论】:

  • 您缺少用于信号声明的(),请参阅Signal to Signal Connect。避免使用与内置信号类似的名称,这可能会产生奇怪的错误。这不是你的情况,但最好避免潜在的问题来源。至于ListView,请考虑使用VisualItemModelObject Instanced as models
  • 谢谢,真的很怀念这个东西。在其他元素中使用没有() 的信号名称(在QML 的几个Qt 教程中看到了这一点)。会为其他人解决这个问题。你的意思是我可以在没有委托的情况下使用VisualItemModel?但是在这种情况下,如何将菜单元素创建为子元素? (正如我在 main.qml 中展示的那样)
  • 使用孩子对我来说似乎很奇怪,因为ListView 本身也是root 的孩子,不是吗?这对我来说听起来很尴尬。
  • 明白,感谢您的建议。将尝试使用其他模型。
  • 没问题,无论如何感谢您的提示。

标签: qt listview delegates qml qtquick2


【解决方案1】:

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

signal <signal_name>()

这也是您收到错误“is not a function”的原因。除此之外,信号/信号处理程序的使用是正确的。无论如何,仔细阅读文档不会受到伤害。 This page 详细介绍了这个论点。

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

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

一个对象定义可以有一个默认属性。默认属性是如果在另一个对象的定义中声明一个对象,则为其分配值的属性,而不将其声明为特定属性的值。

因此,您可以为您的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 中声明的所有Items 都自动成为addItemchildren,这是一个内部声明的@ 987654350@ (2). 这样ListView 是分开的,而所有BreezeQuickMenuItem 都聚集在一起,在addItem children 属性下。此时,使用相同的children 属性就足够了作为model (3) 的ListView 就是这样。

【讨论】:

  • 谢谢,非常好的例子!不知道contents属性的使用,其他的事情也说明了这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-23
相关资源
最近更新 更多