Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Qt 防止;继承的;禁止执行信号处理程序_Qt_Signals_Qml_Handler_Qtquick2 - Fatal编程技术网

Qt 防止;继承的;禁止执行信号处理程序

Qt 防止;继承的;禁止执行信号处理程序,qt,signals,qml,handler,qtquick2,Qt,Signals,Qml,Handler,Qtquick2,在“基本”组件中定义一个信号处理程序是非常巧妙的,因为许多派生组件将经常使用该功能 但是,在QML中,在派生组件中安装新的处理程序并不能替换原始的处理程序,它只是堆叠在它上面。由于处理程序并非每个信号都是唯一的,它们只是连接,每个信号可以有多个连接 一种解决方案是不在基本组件中提供默认处理程序,但是每次使用组件时都必须复制和粘贴该处理程序。那么有更好的方法吗?正如peppe所提到的,一种解决方案是,不直接安装处理程序,只需调用可以重写的函数即可。然而,当打算在派生组件中重用基本实现时,函数重写本

在“基本”组件中定义一个信号处理程序是非常巧妙的,因为许多派生组件将经常使用该功能

但是,在QML中,在派生组件中安装新的处理程序并不能替换原始的处理程序,它只是堆叠在它上面。由于处理程序并非每个信号都是唯一的,它们只是连接,每个信号可以有多个连接


一种解决方案是不在基本组件中提供默认处理程序,但是每次使用组件时都必须复制和粘贴该处理程序。那么有更好的方法吗?

正如peppe所提到的,一种解决方案是,不直接安装处理程序,只需调用可以重写的函数即可。然而,当打算在派生组件中重用基本实现时,函数重写本身是一个混合包,而不一定是在具有组件继承的顺序处理程序堆栈中

实际上,我提出了一个灵活的解决方案,尽管有点笨拙。它是手动断开以前安装的处理程序,并手动连接新的处理程序。这有两个含义:

  • 处理程序不能是匿名表达式,它们必须作为函数实现,以便在断开连接时引用

  • 不能使用声明性语法(
    onSignal:handler()
    )绑定处理程序,因为这不会连接到处理程序函数,而是连接到调用处理程序函数的匿名表达式。所以你不能断开连接

  • 看起来是这样的:

    //BaseComp.qml
    QtObject {
        signal sig(int i)
        function baseHandler(i) {...}
        Component.onCompleted: sig.connect(baseHandler)
    }
    
    //DerivedComp.qml
    BaseComp {
        function derivedHandler(i) {...}
        Component.onCompleted: {
            sig.disconnect(baseHandler)
            sig.connect(derivedHandler)
        }
    }
    
    基本模式是断开覆盖它的每个派生组件中的前一个基本处理程序。通过这种方式,如果需要从派生组件访问基处理程序,那么如果只有一个被重写的处理程序函数,则由于在QML中如何实现重写,将无法从派生类访问基实现(将有两个同名函数作为对象的成员,但它们都将引用派生组件替代)


    如果QML提供了一种创建“唯一”绑定的好方法——在创建新连接之前清除所有以前的连接,那么就不需要所有的变通代码了。

    考虑到在重写QML中的函数时,每个实现都必须有一个不同的名称

    首先为插槽处理程序函数定义一个命名方案,假设onsomethinghappeed在onsomethinghappeed上执行handle,而
    ComponentA
    的实现是handleonsomethinghappeed\u ComponentAHinghapped,它执行基类的实现

    通过这些命名约定,我们可以实现具有一系列优良特性的设置:

  • 多重继承是可能的
  • 可以选择在任何特定点调用基类的实现
  • 类必须只知道其直接基类
  • 调用方代码比实现更好
  • 它很复杂,但并不复杂(和)
  • 我想它可以很容易地生成代码
  • 在第一个示例中,我们有3个按钮来处理单击,1.使用默认实现,2.使用自定义实现,3.使用自定义实现加上基本实现(在任何时候):

    这可以通过如下定义
    BaseButton
    来实现

    Button {
        property var handleOnClicked: superHandleOnClicked
    
        // "super" from the instance's perspective. Use this in implementations of handleOnDoubleClicked
        property var superHandleOnClicked: handleOnClicked_BaseButton
    
        function handleOnClicked_BaseButton() {
            console.log("BaseButton clicked.")
        }
    
        onClicked: handleOnClicked()
    }
    
    基本实现可在函数
    中找到

    带参数的插槽

    使用参数时,不会发生任何更改:

    Rectangle {
        width: 100
        height: 40
        color: "green"
        BaseMouseArea {
        }
    }
    
    Rectangle {
        width: 100
        height: 40
        color: "green"
        BaseMouseArea {
            handleOnDoubleClicked: function(mouse) {
                console.log("Custom click handler", mouse.x, mouse.y)
            }
        }
    }
    
    Rectangle {
        width: 100
        height: 40
        color: "green"
        BaseMouseArea {
            handleOnDoubleClicked: function(mouse) {
                console.log("Custom click handler", mouse.x, mouse.y)
                superHandleOnDoubleClicked(mouse)
            }
        }
    }
    
    BaseMouseArea定义为

    MouseArea {
        anchors.fill: parent
    
        property var handleOnDoubleClicked: superHandleOnDoubleClicked
    
        // "super" from the instance's perspective. Use this in implementations of handleOnDoubleClicked
        property var superHandleOnDoubleClicked: handleOnDoubleClicked_BaseMouseArea
    
        function handleOnDoubleClicked_BaseMouseArea(mouse) {
            console.log("BaseMouseArea clicked", mouse.x, mouse.y, ".")
        }
    
        onDoubleClicked: handleOnDoubleClicked(mouse)
    }
    
    Rectangle {
        width: 100
        height: 40
        color: "blue"
        PointerMouseArea {
        }
    }
    
    Rectangle {
        width: 100
        height: 40
        color: "blue"
        PointerMouseArea {
            handleOnDoubleClicked: function(mouse) {
                console.log("Don't tell father and grandfather", mouse.x, mouse.y)
            }
        }
    }
    
    Rectangle {
        width: 100
        height: 40
        color: "blue"
        PointerMouseArea {
            handleOnDoubleClicked: function(mouse) {
                console.log("Tell father and grandfather", mouse.x, mouse.y)
                superHandleOnDoubleClicked(mouse)
            }
        }
    }
    
    多重继承

    现在我们有了
    instance
    PointerMouseArea
    BaseMouseArea
    ,实例被定义为

    MouseArea {
        anchors.fill: parent
    
        property var handleOnDoubleClicked: superHandleOnDoubleClicked
    
        // "super" from the instance's perspective. Use this in implementations of handleOnDoubleClicked
        property var superHandleOnDoubleClicked: handleOnDoubleClicked_BaseMouseArea
    
        function handleOnDoubleClicked_BaseMouseArea(mouse) {
            console.log("BaseMouseArea clicked", mouse.x, mouse.y, ".")
        }
    
        onDoubleClicked: handleOnDoubleClicked(mouse)
    }
    
    Rectangle {
        width: 100
        height: 40
        color: "blue"
        PointerMouseArea {
        }
    }
    
    Rectangle {
        width: 100
        height: 40
        color: "blue"
        PointerMouseArea {
            handleOnDoubleClicked: function(mouse) {
                console.log("Don't tell father and grandfather", mouse.x, mouse.y)
            }
        }
    }
    
    Rectangle {
        width: 100
        height: 40
        color: "blue"
        PointerMouseArea {
            handleOnDoubleClicked: function(mouse) {
                console.log("Tell father and grandfather", mouse.x, mouse.y)
                superHandleOnDoubleClicked(mouse)
            }
        }
    }
    
    这需要以下
    PointerMouseArea
    的定义:

    BaseMouseArea {
        cursorShape: Qt.PointingHandCursor
    
        superHandleOnDoubleClicked: handleOnDoubleClicked_PointerMouseArea
    
        function handleOnDoubleClicked_PointerMouseArea(mouse, superImplementation) {
            console.log("Pointed at something") // I just add my comment and then call super
            handleOnDoubleClicked_BaseMouseArea(mouse)
        }
    }
    
    你在PointerMouseArea看到的是

  • 它在BaseMouseArea(光标形状)上添加了一些属性
  • 它覆盖了
    super*
    方法来实现它的具体实现
  • 它实现其具体实现并调用父实现

  • 下面提供了以下示例项目:

    您仍然可以在函数中定义代码片段,让子类简单地调用函数。或者提供一些布尔属性来阻止超类处理程序执行任何操作……不知怎的,“漂亮”的想法听起来是错误的。如果基类实现需要基类发出的信号来保持一致的状态,那么就不可能在派生组件中重写它,因为这会破坏基类的设计。但是,如果基类不需要插槽,而只是偶尔在d中保存一些文本行如果是一个已验证的组件,那么在基类中建立连接听起来像是糟糕的设计。我认为,您应该真正考虑类的封装/设计。@Jens-问题不在于组件设计,而在于QML的限制。重写并没有像预期的那样真正起作用,信号接口仅限于连接/断开,而尽管需要表达式引用才能工作,但我不知道您从何处得到这样一个有趣的想法:重写基类实现会“中断”stuff-它一直被大量使用。基类型定义接口和一些功能,派生类型在此基础上构建。在这种情况下,基组件信号是接口的一部分,它提供了一个默认实现。@Jens-在我的特殊情况下,信号是一个
    信号单击(键)
    专为处理我的自定义事件传播方案而设计。90%的时间,对象都在列表中,因此使用arro