Qt 防止;继承的;禁止执行信号处理程序
在“基本”组件中定义一个信号处理程序是非常巧妙的,因为许多派生组件将经常使用该功能 但是,在QML中,在派生组件中安装新的处理程序并不能替换原始的处理程序,它只是堆叠在它上面。由于处理程序并非每个信号都是唯一的,它们只是连接,每个信号可以有多个连接Qt 防止;继承的;禁止执行信号处理程序,qt,signals,qml,handler,qtquick2,Qt,Signals,Qml,Handler,Qtquick2,在“基本”组件中定义一个信号处理程序是非常巧妙的,因为许多派生组件将经常使用该功能 但是,在QML中,在派生组件中安装新的处理程序并不能替换原始的处理程序,它只是堆叠在它上面。由于处理程序并非每个信号都是唯一的,它们只是连接,每个信号可以有多个连接 一种解决方案是不在基本组件中提供默认处理程序,但是每次使用组件时都必须复制和粘贴该处理程序。那么有更好的方法吗?正如peppe所提到的,一种解决方案是,不直接安装处理程序,只需调用可以重写的函数即可。然而,当打算在派生组件中重用基本实现时,函数重写本
一种解决方案是不在基本组件中提供默认处理程序,但是每次使用组件时都必须复制和粘贴该处理程序。那么有更好的方法吗?正如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,它执行基类的实现
通过这些命名约定,我们可以实现具有一系列优良特性的设置:
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看到的是
super*
方法来实现它的具体实现下面提供了以下示例项目:您仍然可以在函数中定义代码片段,让子类简单地调用函数。或者提供一些布尔属性来阻止超类处理程序执行任何操作……不知怎的,“漂亮”的想法听起来是错误的。如果基类实现需要基类发出的信号来保持一致的状态,那么就不可能在派生组件中重写它,因为这会破坏基类的设计。但是,如果基类不需要插槽,而只是偶尔在d中保存一些文本行如果是一个已验证的组件,那么在基类中建立连接听起来像是糟糕的设计。我认为,您应该真正考虑类的封装/设计。@Jens-问题不在于组件设计,而在于QML的限制。重写并没有像预期的那样真正起作用,信号接口仅限于连接/断开,而尽管需要表达式引用才能工作,但我不知道您从何处得到这样一个有趣的想法:重写基类实现会“中断”stuff-它一直被大量使用。基类型定义接口和一些功能,派生类型在此基础上构建。在这种情况下,基组件信号是接口的一部分,它提供了一个默认实现。@Jens-在我的特殊情况下,信号是一个
信号单击(键)
专为处理我的自定义事件传播方案而设计。90%的时间,对象都在列表中,因此使用arro