I'm using QML with a webengineview container and that webengineview container is killed sometimes (when CPU is high).
My question is, how can I detect with QML the app entered in discarded state for reloading the container?
One way to do it would be like this:
WebEngineView {
onLifecycleStateChanged: {
if (lifecycleState === LifecycleState.Discarded) {
// Do something
}
}
}
Or if you need to listen for the state from a different object, you can use a Connections object:
Connections {
target: myWebEngineView
onLifecycleStateChanged: {
if (lifecycleState === LifecycleState.Discarded) {
// Do something
}
}
}
Or, you could simply bind a property directly to the state and use it however you want to:
property bool isDiscarded: myWebEngineView.lifecycleState === LifecycleState.Discarded
Related
How can component inform parents when certain action happens? I mean something like event.buble in JavaScript. https://www.w3docs.com/learn-javascript/bubbling-and-capturing.html
For example some elements in dialog can send a "Ok" or "Cancel" action.
Parent item does not know all the child items items in advance. I would add something like:
Widget {
signal cancel
signal ok
...
}
ParentItem {
id: myParentItem
onCancel { ... }
onOk { ... }
Widget {
id: first
}
Widget {
id: second
}
// no connection section needed. Auto-connect signals by name.
}
}
Edit:
Note: adding separate Widget and then connection is a bit impractical. Some one can forget to add one or other, moreover when deleting and renaming one can remove only one part or rename one part incorrectly.
Calling parent.functionName is impractival too because then such Widget can be used only in parents having functionName.
One idea is to search through all the children and check their type. If they are the Widget type, then connect their signals to some ParentItem function. I haven't tested this code, but something like it should work.
ParentItem {
id: myParentItem
function doCancel() { ... }
function doOk() { ... }
Component.onCompleted: {
for (var i = 0; i < children.length; i++) {
if (children[i] instanceOf Widget) {
children[i].onOk.connect(doOk);
children[i].onCancel.connect(doCancel);
}
}
}
Widget {
id: first
}
Widget {
id: second
}
}
I need to perform some actions in let's say main.qml according to button press in button.qml. Button inside of the button QML is inside of some custom object. Let's give it a name customObject. So customObject in button.qml looks like this:
customObject {
id:trialObject
signal backPagePressed()
Button {
id:button1
MultitouchArea {
onPressed:
{
trialObject.backPagePressed()
}
Now when I press the button, it emits backPagePressed(). My question is: How can I make a slot for this signal in main QML? I'm familiar to signal and slot mechanism in C++, but that does not work for QML. I made something like this in main.qml:
Loader
{
id:pageLoader
onBackPagePressed:
{
pageLoader.source =""
}
}
That part needs to delete the Loader's source so that it will go back to page before. However, I'm not sure about onBackPagePressed: ... How can I connect my signal backPagePressed, to the related part in my loader?
You should use a Connections object (documented here) together with the item property of the Loader:
Loader {
id: pageLoader
source: "CustomObject.qml"
}
Connections {
target: pageLoader.item
//Qt < 5.15
onBackPagePressed: pageLoader.source = ""
//Qt >= 5.15
function onBackPagePressed()
{
pageLoader.source = ""
}
}
I've been trying to wrap my head around this one for a while and came up with a few hacks, but none of them seem to be the Right Way. Hopefully this makes sense. Say I have three qml files.
First QML:
...
ListView {
id: patientList
model: patientModel
delegate: E3DPatientListItem {
onClicked: {
if (patientList.currentIndex !== index)
{
patientList.currentIndex = index
detailStackView.push("DetailPanel.qml",
{ "view": view, "ptInfo": model })
...
DetailPanel:
...
Page {
property QtObject ptInfo
Timeline {
ptInfo: ptInfo // <- how do I pass this to Timeline?
...
Timeline.qml
...
Item {
property QtObject ptInfo // <- always null :(
...
...
Page {
property QtObject ptInfo
Timeline {
ptInfo: ptInfo // <- how do I pass this to Timeline?
...
What do you suppose ptInfo: ptInfo is achieving? You are binding the property to its own identifier.
Maybe try not using the same identifier to avoid shadowing, or give the Page and id and then ptInfo: pageid.ptInfo. parent.ptInfo will also work as long as the object has the parent property exposed, keep in mind that QtObject does not.
However, you don't really need to have property QtObject ptInfo in Timeline.qml, as long as a timeline is always instantiated inside a page, you can access ptInfo directly from inside the timeline because of dynamic scoping. Note that dynamic scope properties will only work for properties that are defined in the root element of the particular qml file:
// Obj1.qml
Item {
property int test: 7
Obj2{}
}
// Obj2.qml
Item {
Component.onCompleted: console.log(test) // it will work
}
When I define a Component in QML I can define a alias property to expose properties of QtObjects that are otherwise hidden by the Components root.
Especially interesting is the default property alias to build powerful reusable and adaptable Components. But there is no generic way to have alter the nameresolution, which is bad for properties and signals.
Example: MyComp1.qml
Item {
id: rootItem
default property alias content: childItem.data
signal sig()
Item {
id: childItem
}
}
main.qml
MyComp {
id: myObj
signal sig1()
onSig1: console.log('here')
Button {
id: button
onClicked: {
parent.sig()
parent.sig1()
}
}
}
Here button is now a child of childItem, but both signals: sig() and sig1() are defined in rootItem, which leads to an error. To the user of of my nicely designed Component it is not transparent. He would need to look in the code of the Component to realize, why the buttons parent is not myObj/rootItem but in fact of childItem. This might lead to bugs.
Therefore I am looking for a way to prevent it.
For signal sig() this would be possible by the modifying the MyComp and manually forward the signal from childItem to rootItem:
Item {
id: rootItem
default property alias content: childItem.data
signal sig()
Item {
id: childItem
signal sig()
onSig: rootItem.sig()
}
}
But is there a way to shortcut this, so that the user does not need to us myObj.sig1() but might use parent.sig1().
Same goes for properties, that are added uppon instantiation:
MyComp {
signal sig1()
property int num: 5
Button {
text: parent.num // <--- Error
}
}
It would be nice, if the properties and signals defined uppon instantiation would be available as parent.propertyName to the Objects added by a default-property aswell, I think.
Is there a way (to maybe hack this)?
There is no way to do this.
What you can do is stop assuming the outer scope in QML code is always the parent.
You could either access it directly by id:
MyComp {
id: myComp
signal sig1()
property int num: 5
Button {
text: myComp.num
onClicked: myComp.sig1()
}
}
Or if the object you want to access is the root item, you can access its properties implicitely:
MyComp {
signal sig1()
property int num: 5
Button {
text: num
onClicked: sig1()
}
}
One good practice (albeit maybe too extreme for most case) that can be deduced from this situation, is to only use parent when you actually want to access the parent Item in the visual hierarchy, for things like anchors or width and height.
Focus events don't work because they're not sent if you activate your window by clicking on its non-client frame. Also, if you click the internal components of the window THEY will get the focus event, not your window, but the window will still be activated, even if it wasn't active or focused before.
The event you want is QEvent::WindowActivate. Override event() to process it:
bool YourWidget::event(QEvent *e)
{
if (e->type() == QEvent::WindowActivate) {
// window was activated
}
return QWidget::event(e);
}
Qt provides several virtual event handling functions you can use. Since the activation of a window changes its state, you want to handle some change events:
void MyWidget::changeEvent(QEvent * e) {
if(e->type() == QEvent::ActivationChange && this->isActiveWindow()) {
// .. this is now the active window
}
}
References
changeEvent
isActiveWindow