QML子窗口未按预期关闭

时间:2014-09-18 09:05:37

标签: qt qml

我尝试将子窗口实现为弹出窗口,当用户点击它时,该子窗口应该会消失。按照this question设置的示例,我想出了这个:

import QtQuick 2.3
import QtQuick.Window 2.2

Window {
    id: win
    width: 360
    height: 360
    color: "black"

    Rectangle {
        id: block
        width: 20
        height: 20
        color: "green"

        MouseArea {
            anchors.fill: parent
            hoverEnabled: true

            onEntered: {
                console.log( "Entered" );
                menu.visible = true;
                menu.requestActivate();
            }
        }

        Window {
            id: menu
            width: 100
            height: 100
            x: win.x + block.width
            y: win.y + block.height

            flags: Qt.Popup
            color: "red"
            visible: false

            onActiveChanged: {
                console.log( "Pop up:", active );
                if ( !active ) {
                    visible = false;
                }
            }
        }
    }

    onActiveChanged: {
        console.log( "Main win:", active );
    }
}

但是,在外部单击时,弹出窗口不会消失,调试输出为:

// Main win opens
qml: Main win: true

// Green square entered
qml: Entered
qml: Main win: true
qml: Pop up: true

// Clicked outside of the pop up
qml: Pop up: true
qml: Main win: true

正如您所看到的,当弹出窗口变为活动状态时,主窗口会失去焦点,因此当用户在其外部单击时,整体焦点不会改变。那么这种方法应该如何运作呢?

1 个答案:

答案 0 :(得分:0)

我发现的解决方案感觉相当hackish,但它有效,它是独立的,并且可以扩展。

import QtQuick 2.3
import QtQuick.Window 2.2

Window {
    id: win
    width: 360
    height: 360
    color: "black"

    Rectangle {
        id: block
        width: 20
        height: 20
        color: "green"

        MouseArea {
            anchors.fill: parent
            hoverEnabled: true

            onEntered: {
                menu.visible = true;
            }
        }

        Rectangle {
            id: menu
            width: 100
            height: 100

            anchors.top: parent.bottom
            anchors.left: parent.right

            color: "red"
            visible: false

            Loader {
                id: exitAreaLoader
                Component {
                    id: exitArea

                    MouseArea {
                        x: 0
                        y: 0
                        parent: menu.getRoot()
                        width: if ( parent !== null ) { return parent.width }
                        height: if ( parent !== null ) { return parent.height }

                        onPressed: {
                            var pnt = Qt.point( mouse.x - menu.parent.width,
                                                mouse.y - menu.parent.height );
                            if ( !menu.contains( pnt ) )
                            {
                                console.log( "Closing", pnt );
                                menu.visible = false;
                                exitAreaLoader.sourceComponent = undefined;
                            } else {
                                mouse.accepted = false;
                            }
                        }
                    }
                }
            }

            onVisibleChanged: {
                if ( visible ) {
                    console.log( "Opening" );
                    exitAreaLoader.sourceComponent = exitArea;
                }
            }

            function getRoot() {
                var par = parent;
                while ( par.parent !== null ) {
                    par = par.parent;
                }

                return par;
            }
        }
    }
}

一般原则是,当菜单/弹出/下拉菜单可见时,Loader会创建MouseArea作为整个QObject树中最后代的子项(这可以保证窗口内的所有鼠标事件都将被它接收。但是,这意味着MouseArea也会捕获指向弹出窗口所包含的任何鼠标事件,因此我们必须明确测试并拒绝该事件。

真的很遗憾没有官方对象,one was requested years ago并且它似乎有adopted by Ubuntu,但这对于跨平台开发来说并不是很有用。