在许多派生组件经常使用该功能时,在“基础”组件中定义信号处理程序非常有用。
但是,在QML中,在派生组件中安装新处理程序不会替换原始处理程序,它只是堆叠在它之上。由于处理程序并非每个信号都是唯一的,它们只是连接,每个信号可以有多个连接。
一种解决方案是简单地不在基本组件中提供默认处理程序,但是每次使用组件时都必须复制并粘贴处理程序。那么有更好的方法吗?
答案 0 :(得分:1)
正如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提供了一种非常好的方式来制作一个“独特的”绑定,那将是很好的和有用的 - 在制作新的连接之前清除所有先前的连接。然后,不需要所有变通方法代码。
答案 1 :(得分:0)
鉴于在QML中覆盖函数时,the base implementation is no more available使得每个实现必须有一个不同的名称。
首先为插槽处理程序函数定义命名方案,让我们说 onSomethingHappened 执行 句柄 OnSomethingHappened 。 ComponentA
的实施是 句柄 OnSomethingHappened _ComponentA 。在handleOnSomethingHappened
中有 superHandle OnSomethingHappened ,它执行基类'实施
通过这些命名约定,我们可以实现一系列不错的属性设置:
在第一个例子中,我们有3个按钮来处理点击,1。使用默认实现,2。使用自定义实现和3.使用自定义实现加基础实现(在任何时候):
BaseButton {
text: "Button 1"
}
BaseButton {
text: "Button 2"
handleOnClicked: function() {
console.log("Custom click handler")
}
}
BaseButton {
text: "Button 3"
handleOnClicked: function() {
console.log("Custom click handler")
superHandleOnClicked()
}
}
这可以通过像这样定义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()
}
基本实现在函数superHandleOnClicked
中可用。
带参数的插槽
使用参数时,没有任何变化:
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)
}
多重继承
现在我们instance
是 PointerMouseArea
是 BaseMouseArea
,实例定义为
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*
方法的具体实现此处提供了foll示例项目:https://github.com/webmaster128/derived-qml-slots