Defining a signal handler in a \"base\" component is pretty nifty when that functionality is going to be frequently used by many derived components.
However, in QML
Given that when overriding functions in QML, the base implementation is no more available such that there must be a distinct name for each implementation.
First define a naming scheme for slot handler functions, let's say onSomethingHappened executes handleOnSomethingHappened. And ComponentA
's implementation is handleOnSomethingHappened_ComponentA. In handleOnSomethingHappened
there is superHandleOnSomethingHappened, which executes the base class' implementation.
With these naming conventions we can achieve a setup with a bunch of nice properties:
In the first example we have 3 Buttons that handle clicks, 1. using the default implementation, 2. using a custom implementation and 3. using a custom implementation plus the base implementation (at any point):
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()
}
}
This can be done by defining BaseButton
like this
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()
}
The base implementation is available in the function superHandleOnClicked
.
Slots with arguments
When arguments are used, nothing changes:
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)
}
}
}
with BaseMouseArea defined as
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)
}
Multiple inheritance
Now we have instance
is a PointerMouseArea
is a BaseMouseArea
, with instance being defined as
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)
}
}
}
which requires the following definition of 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)
}
}
What you see in PointerMouseArea is
super*
methods to it's concrete implementationThe foll sample project is available here: https://github.com/webmaster128/derived-qml-slots