QML 中的类似菜单栏的行为

Posted

技术标签:

【中文标题】QML 中的类似菜单栏的行为【英文标题】:MenuBar like behaviour in QML 【发布时间】:2016-08-04 05:04:54 【问题描述】:

我希望在单击矩形时具有类似菜单栏的行为。每当单击矩形时,模型就会更新并显示ListView。我希望这个ListView 在点击另一个Rectangle 时消失,并且每次点击都不应该附加listmodel。这是我的示例代码。

Card.qml

Rectangle 
    id: card
    width: 50
    height: 100
    color: "pink"
    Item 
        id: rec
        width: 50
        anchors.bottom: parent.top

        ListModel 
            id: menuListModel
        

        Component 
            id: delegate
            Rectangle 
                width: 50
                height: 20
                color: "blue"
                Text 
                    anchors.fill: parent
                    anchors.centerIn: parent
                    text: commandText
                
            
        

        ListView 
            anchors.fill: parent
            model:menuListModel
            delegate: delegate
            interactive: false
        
    

    MouseArea 
        anchors.fill: parent
        onClicked: 
            rec.height += 40;
            menuListModel.append("commandText" : "Act");
            menuListModel.append("commandText" : "Set");
        
    

ma​​in.qml

Item 
    width: 120
    height: 200
    Row 
        anchors.bottom: parent.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        spacing: 10
        Card 
            id: card1
        
        Card 
            id: card2
        
    

我还想在单击菜单按钮时调用某些功能,即ActSet

编辑

点击卡片(此处为矩形)时,会使用适当的标志调用以下函数。

property int command_activate:  0x0001
property int command_summon:    0x0002
property int command_spsummon:  0x0004
property int command_mset:      0x0008
property int command_sset:      0x0010
property int command_repos:     0x0020
property int command_attack:    0x0040
property int command_list:      0x0080

function showMenu(flag) 
    if(flag & command_activate) 
        rec.height += 15;
        menuListModel.append("commandText" : "Activate");
    
    if(flag & command_summon) 
        rec.height += 15;
        menuListModel.append("commandText" : "Normal Summon");
    
    if(flag & command_spsummon) 
        rec.height += 15;
        menuListModel.append("commandText" : "Special Summon");
    
    if(flag & command_mset) 
        rec.height += 15;
        menuListModel.append("commandText" : "Set");
    
    if(flag & command_sset) 
        rec.height += 15;
        menuListModel.append("commandText" : "Set");
    
    if(flag & command_repos) 
        if(position & pos_facedown) 
            rec.height += 15;
            menuListModel.append("commandText" : "Flip Summon");
        
        else if(position & pos_attack) 
            rec.height += 15;
            menuListModel.append("commandText" : "To Defense");
        
        else 
            rec.height += 15;
            menuListModel.append("commandText" : "To Attack");
        
    
    if(flag & command_attack) 
        rec.height += 15;
        menuListModel.append("commandText" : "Attack");
    
    if(flag & command_list) 
        rec.height += 15;
        menuListModel.append("commandText" : "View");
    
  

因此,简而言之,当点击卡片时,必须根据卡片顶部的flag 显示菜单。

【问题讨论】:

【参考方案1】:

您的代码有几个问题。

您不能将您的delegate 命名为“代表”。当你这样做时,ListView 使用它自己的委托属性来设置自己,导致没有任何事情发生。

另外,你为什么不静态填充你的ListView,然后使用visible 属性来切换是否显示它?如果您希望它在单击另一个Card 时消失,您可能必须使用focus 属性。

确实,将焦点设置为 true 将重置焦点范围内所有其他项目的焦点。这样的事情可能会起作用:

Rectangle 
    id: card
    ...
    property alias model: list.model

    Component 
        id: mydelegate
        Rectangle 
            width: 50
            height: 20
            ...
        
    

    ListView 
        id: list
        visible: card.activeFocus
        anchors.bottom: parent.top
        width: card.width
        delegate: mydelegate
        interactive: false
        height: childrenRect.height
    

    MouseArea 
        anchors.fill: parent
        onClicked: 
            card.focus = !card.focus
        
    

至于调用函数,可以在ListModel中直接添加要调用的函数名。在您的委托中添加MouseArea,并在单击时发送信号。然后,您只需调用匹配的插槽(同意,this[slot]() 语法有点 hacky)。

在 Card.qml 中

Rectangle 
    id: card
    ...

    property alias model: list.model
    signal itemClicked(string slot)

    Component 
        id: mydelegate
        Rectangle 
            ...
            MouseArea
            
                anchors.fill: parent
                onClicked: 
                    if(model.slot)
                        itemClicked(slot)
                
            
        
    

    ...

在 main.qml

    ...
    Card
    
        model: ListModel 
            ListElementcommandText: "Act"; slot: "act"
            ListElementcommandText: "Set"; slot: "set"
        

        function act()
        
           print("act triggered")
        

        function set()
        
           print("set trigggered")
        

        onItemClicked:  this[slot]() 
    
    ...

【讨论】:

delegate 用作id 对我来说是一个糟糕的判断。我无法静态填写我的ListView,因为有很多按钮,如ActSetSummon 等,每个按钮的可见性都由一个函数决定。所以它是一个动态模型。 您能否提供有关如何确定可见性的更多信息?也许用代码示例编辑你的答案【参考方案2】:

由于我无法发表评论,要求澄清,我将根据我的理解陈述我的假设:

您有多个ListModel,其中包含在单击栏中相应的矩形项时应弹出的菜单信息。 一旦您单击此栏中的任何其他矩形,弹出的 ListView 将消失。 (另外:如果点击了栏或菜单之外的东西?或者选择了栏中的某个项目?)

我只会使用一个 ListView,并在单击按钮后更新/更改模型以及位置(例如边距),因此您不会有多个未使用的对象飞来飞去。 不显示任何东西,我认为设置一个空模型就足够了。

你也可以有一个函数列表。

Row 
    id: row
    property var f: [a, b, c]
    function a()  console.log('a'); 
    function b()  console.log('b'); 
    function c()  console.log('c'); 
    width: 300
    height: 50
    Repeater 
        id: rep
        anchors.fill: parent
        delegate: button
        model: 3
        Rectangle 
            id: button
            width: 98
            height: 50
            border.color: 'black'
            Text 
                text: "a"
                anchors.fill: parent
            
            MouseArea 
                anchors.fill: parent
                onClicked: row.f[index]()
            
        
    

例如将调用函数 a、b 或 c - 取决于矩形的索引。

希望到目前为止,我能提供帮助。

【讨论】:

以上是关于QML 中的类似菜单栏的行为的主要内容,如果未能解决你的问题,请参考以下文章

向下滚动以逐渐隐藏菜单栏或视图并向上滚动

需要一个用于垂直菜单栏的 jquery 插件

Qt:Mac 菜单栏的怪异之处

QML - 通过点击事件显示菜单栏或菜单项

菜单栏的VC菜单

顶部栏的自定义下拉菜单[关闭]