QML Calendar : Programmatically call onClicked handler - qt

My QML application is displaying a Calendar element.
When the selected date is changed (clicked), I need to update an other element (an image).
I have something like this:
Calendar {
id: calCalendar
onClicked: {
// update other QML element
}
}
It works fine when the user click with the mouse on the calendar: the other element (the image) is correctly updated.
My problem is initialization : when my app is started, the calendar displays the current date by default, and I'd like to programmatically call the onClicked handler, to make sure the image is up to date.
I don't know how to do that.

If you want to do something when a QML component is done initializing you can use the Component.onCompleted : slot.
Calendar {
id: calCalendar
onClicked: {
// update other QML element
}
Component.onCompleted: {
// Do stuff for initialization.
// you could do this here : calCalendar.Clicked()
// if you want to use the same code for initialization and for user input handling later on.
}
}
The point is the following : onXXX : { declares a slot to handle the singal XXX. Here the signal is Clicked. You can trigger the signal programmatically as you say, just by invoking it like a function. You'll need to know a valid overload for the arguments (if any).

Related

How to find subsequent (all) SLOT from a subclass

I need to block specific buttons on an MMI.
I implemented a button blocking function in a subclass of QPushButton.
For this, I used the clicked() signal and blocked the button with blockSignals(true).
This means that with each button clicked on my MMI, 2 SLOTS are always called.
But when calling the blocking of a specific button, I get the first SLOT (clicked()) of my subclass, in which I block the button, then I then arrive in the original SLOT linked to this button, which is still called despite the blocking (the first time only).
How can I in my QPushButton subclass know the subsequent SLOTs linked to this button and avoid them (delete them)?
void QbtnStandardButton::slotButtonClicked(void)
{
if (modeProtection)
{
// Special mode to protect/unprotect the button
if (isProtected())
{
// Reset the protection
this->blockSignals(false);
}
else
{
// Set the protection: button will be unclickable
this->blockSignals(true);
}
modeProtection = false;
}
if (isProtected())
{
QMessageBox *pMsgBox = new QMessageBox(QMessageBox::Information,
"Protection",
"This button is protected!",
QMessageBox::Ok);
pMsgBox->exec();
pMsgBox->deleteLater();
// Here: remove subsequent SLOT of this button ?
}
}
I think it's very difficult if not impossible to find SLOTS linked to a button.
I worked around the problem by using an eventFilter() instead of a SIGNAL() in my base class.
In this case, I can filter the "clicked()" event before it is reissued.

QML - Capture all UI events of children objects

In my QML project, I need an object to capture all the UI events of its children objects. So, if any of its children register a click or something, the parent object needs to know about it. The issue here is that all of the children objects are pre-defined classes such as MyButton or MyComboBox. These classes all have defined MouseAreas and onClicked() functions that can't be overridden. Therefore, I need the parent object to capture all the events of its children WITHOUT modifying the MouseAreas of the children. Please let me know the best way to accomplish this.
You can crawl the object tree, connecting a function to every onClicked-signal.
For this we need three parts:
The signal that shall be connected
The function that does the crawling
A function that creates another function to call the signal with custom arguments.
I chose, that my signal shall have to arguments: sender and arguments. Sender is the object, that I clicked on, and arguments are the arguments of the clicked-signal of the clicked object. This is empty for QtQuick.Controls 2.x Buttons and contains one entry (mouse) for MouseAreas.
signal somethingWasClicked(var sender, var arguments)
As this signal has not the same signature as clicked for every clickable object, we can't connect it directly to this signal. We need a intermediary function that calls the signal for us, has the needed arguments in it's scope and has no arguments. We need to build this dynamically for each object we spy on.
function createSpyFunction(object) {
return function() { somethingWasClicked(object, arguments) }
}
And lastly for the crawl-function. We need to store the function we create somewhere. For this I utilize the fact that all QtObjects are JS-Objects in some sense, so I can use Object.defineProperty to dynamically add JS-properties to them. Here I can store our function, without the need of modyfing the sourcecode of the components them selves.
After creating this function, I connect it to the onClicked-handler.
function crawlChildren(obj) {
if (obj.onClicked) {
Object.defineProperty(obj, '__clickedFunction', { value: createSpyFunction(obj) })
obj.onClicked.connect(obj.__clickedFunction)
}
if (obj.children) {
var i = 0
for (; i < obj.children.length; i++) {
crawlChildren(obj.children[i])
}
}
}
This function I finally call in
Component.onCompleted: crawlObj(this.contentItem)
of the root ApplicationWindow of my programm.
As I only call it in the Component.onCompleted-handler, objects that will be added after this, won't be spied uppon. To change this, we will also need to spy on onChildrenChanged, and crawl the newly added objects as well. The process there is almost similar, so this is left as an exercise to the user, or might be subject to a new question.
You can try to overlay your items with a MouseArea. In the event handlers you can check the position and call the event handlers of the underlying items.
Item {
MyButton { id: mybutton
/* set the anchors */
}
MyMouseComboBox { id: myMouseComboBox
/* set the anchors */
}
MouseArea {
anchros.fill: parent
onClicked: {
// mouse.accepted = false
// Check whether clicked point is within mybutton
// on true, call mybutton.doSomething()
// or call mybotton.onPressed(mouse)
}
}

How to receive keyboard events in an unfocused QtQuick Item?

I want to use a press-and-hold behaviour to switch states of a gui Item.
I use a FocusScope(below) to recieve keyboard events.
FocusScope{
id:pageFocus
property var pedalKey//a key id
Keys.enabled: true
Keys.onPressed: {
if(event.key===pedalKey && !event.isAutoRepeat)
{
state="a"
}
}
Keys.onReleased: {
if(event.key===pedalKey && !event.isAutoRepeat)
{
state="b"
}
}
}
It works, but when FocusScope loses the focus.
The most terrible thing is that I don't know which Item got the focus.
Is there any way to enable the Item to receive keyboard events without focus?
You can forward key events to other objects (even multiple objects). Here is the example from Qt's documentation:
Item {
ListView {
id: list1
// ...
}
ListView {
id: list2
// ...
}
Keys.forwardTo: [list1, list2]
focus: true
}
It works, but when FocusScope lost the focus.
Yes, key events are only delivered to the items with activeFocus. The event will be sent to the inner-most item first, proceeding up the chain of parents until one of them accepts the events (using e.g. the handlers you're using here).
The most terrible thing is that I don't know which Item got the focus.
You can use the Window.activeFocusItem attached property to see where the focus is currently.
Is there any way to enable the Item to receive keyboard events without focus?
Not easily or directly. You could use event filtering to intercept events before they get to the window, but I would consider that absolutely an option of last resort. Shortcuts are another possibility, depending on what presses you are trying to intercept.

QML: How to implement signal handler of a child

I'm editing a component in Qt Creator. It suggested me to split the component in UI and not UI parts. My components exposes 2 custom properties.
ComponentViewForm {
property string step: '0'
property string setStep: '0'
}
A TextInput inside the UI-Part is bound to step
It should set the property setStep in onAccepted handler.
First one is easy. The binding can be edited in UI-Editor directly
But how do I implement the signal-handler of the child?
I've implemented it directly in the UI.
TextInput {
id: step
text: parent.step
onAccepted:
{
parent.setStep = text
}
}
It works, but Qt-Creator rejects to open it in UI-mode any more.
You can export the TextInput from your ComponentViewForm. There's a small Export button in the Navigator tab in Qt Quick UI forms editor. Assume that the id of TextInput is stepInput, ComponentViewForm.ui.qml should have an alias property property alias stepInput: stepInput in source code after you click the Export button.
You can implement property binding and signal handlers in ComponentView.qml like this:
ComponentViewForm {
property string step: '0'
property string setStep: '0'
stepInput.text: step
stepInput.onAccepted:
{
setStep = stepInput.text;
}
}

How to check if qml component object (that is created dynamically) has been created?

I have a component that should be created dynamically.
Component {
id: myComponent
Rectangle {
id: letItBeRect
}
}
I want to create it dynamically (when some button clicked) in a function like this:
function loadComponent() {
myComponent.createObject(root); //root is some root component, doesn't matter
}
I have state for root component that depends on some letItBeRect property:
state: letItBeRect.visible ? "visible" : "hidden"
So the question is how do I check if letItBeRect has been created, so I could assign a proper value to "state" property of root component?
I get "ReferenceError: letItBeRect is not defined" so far, which is expected from this code snippet.
P.S. This is not the real code I have, because I don't want to put commercial code here. Thank you

Resources