ListView信号和菜单元素的插槽

时间:2015-06-30 10:37:10

标签: qt listview delegates qml qtquick2

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

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

    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
      }
      

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

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

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

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

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

1 个答案:

答案 0 :(得分:3)

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

形式
signal <signal_name>()

这也是您收到错误&#34; is not a function&#34;的原因。除此之外,信号/信号处理器的使用是正确的。无论如何,仔细阅读文档不会有什么坏处。 This page详细介绍了论点。

回到另一个问题,你做了一个错误的假设:在组件中声明的任何东西都是组件本身的children的一部分。在这里,您声明了BreezeQuickMenu,其中有一个孩子ListView。当您使用它并添加BreezeQuickMenuItem时,您可以将它们添加到ListView所属的相同集中。最后,您在children属性中有四个元素。另外,通过ListViewmodel添加到本身,你会搞砸到完全不相关的字符串呈现的点。

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

  

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

因此,您可以为default定义BreezeQuickMenu属性,并利用它来获取列表所需的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)中我们说&#34;在Item内声明的所有BreezeQuickMenu都是children } addItem这是一个内部声明Item(2)。通过这种方式,ListView保持分开,而所有BreezeQuickMenuItemaddItem children属性下聚集在一起。此时,对children使用与model(3)相同的ListView属性就足够了。