Qt quick how to connect signal and slots from different file - qt

I'm new to QML.
I want to connect a signal from a .qml file to a slot in another .qml.
The problem is that I haven't instantiate the object in that file because I want to use a StackView in the main.qml to see on the screen the objects in that .qml files.
in main.qml I have:
StackView {
id: mStackId
anchors {
top: topSectionId.bottom
bottom: parent.bottom
left: parent.left
right: parent.right
}
initialItem: homePage
}
Component {
id: homePage
Home {id: homePageObj}
}
Component {
id: housePage
House {id: housePageObj}
}
Component {
id: createRoomPage
CreateRoom {id: createRoomPageObj}
}
where Home, House and CreateRoom are the .qml files I want to make to connect.
I've tried:
Component.onCompleted:
createRoomPage.newRoom.connect(homePage.createNewRoom)
where newRoom is the signal and createNewRoom is the slot, but Qt Creator gives me the error:
TypeError: Cannot call method 'connect' of undefined
I've also tried to use createRoomPageObj instead of createRoomPage and homePageObj instead of homePage but I get the error:
ReferenceError: createRoomPageObj is not defined
I've read I could use Connections, but documentation is not too clear to me.

This is not a matter of wrong Connections usage, the createRoomPage simply is not instantiated. You need a backend which can do the logic and to which you can connect from the views.
In the simplest form, you can make a QtObject
QtObject {
id: backend
signal newRoom(name)
}
StackView {
...
}
You can use backend.newRoom("Kitchen") from the CreateRoomPage.
EDIT after question about persistence
You can also create the QObject as a singleton:
pragma Singleton
import QtQuick 2.4
QtObject {
signal newRoom(name)
}
In this case the filename will determine the name to use in the rest of the program. So if naming above piece of code Backend.qml, you can use as follows:
Connections {
target: Backend
function onNewRoom(name) { .... }
}

Related

Does QtObject have a destroy() method?

This code runs without error:
import QtQuick 2.6
import QtQuick.Window 2.2
Window {
visible: true
QtObject {
id: foo
}
Component.onCompleted: {
foo.destroy()
}
}
But the docs for QtObject don't say it has a destroy() method. So does it?
The destroy() method is for deleting dynamically created objects in QML. The QtObject in your example is statically created, and the above documentation says that you cannot call destroy() on such objects:
This would result in an error, since objects can only be dynamically destroyed if they were dynamically created.
I am not sure why you do not get an error in your example, but this is definitely not something you should do.

calling javascript in another file in qml

I am trying to override the onClosing event in a QML application window.
The qml for the window is simple as:
ApplicationWindow {
id: rootWindow
objectName: "window"
visible: true
width: 800
height: 480
property Component loginForm: LoginView {}
onClosing: {
loginForm.logout()
}
}
The LoginView view is simple as well:
Rectangle {
id: view
function logout() {
console.log("Logout called");
}
}
Now, as is, it returns an error:
TypeError: Property 'logout' of object QQmlComponent(0x9287150) is not a function
I also tried loginForm.view.logout() and this returns in:
TypeError: Cannot call method 'logout' of undefined
I believe QML is having trouble because your property is of type Component. You are assigning a LoginView, which is an inheritance descendent of Component, to a property of type Component. If you change your property to be of type LoginView, it will work:
property LoginView loginForm : LoginView{}
If this isn't actually a property that you want to be exported by the main module, you can simply instantiate it without creating a property, but still giving it a module-scope identifier:
LoginView{ id: loginForm }
Doing either of these will give you access to that function.

Undefined reference on a binding to id, Scoping rules

I am trying to pass around an object required by some qml components. The problem is that I cannot reference this object without it saying its undefined.
Item {
id: root
property alias db: database // this works for some reason
Database {
id: database
Component.onCompleted: {
connect("sqlite3", "dbname=database.db")
deleteTables();
createTables();
}
}
ContactImageProvider {
id: contactImageProvider
database: db // this works for some reason
database: root.database // This would be undefined
database: database // no loop detected but still null
}
}
So I am very very confused how I am supposed to be able to pass dependencies down though objects without the most confusing naming scheme ever. This could be anything BTW. Maybe I need a color in some control but want to pass it to another control as well. The whole scope name resolution documentation is very unclear. I can't make heads or tails what I'm supposed to be able to do.
Item {
id: root
property Database database: Database {
id: database // if no id then this doesnt work
Component.onCompleted: {
connect("sqlite3", "dbname=database.db")
deleteTables();
createTables();
}
}
property alias db: database
ContactImageProvider {
id: contactImageProvider
database: db // this doesn't work. WHY? idk
database: database // works if id is on
}
}
Also aliasing doesn't seem to work if I make it a property.
To any poor soul after me, it seems that this has to do with the differences between how property names and id names are resolved. What I ended up with was this.
Item {
id: root
property Database database: Database {
// notice no id
Component.onCompleted: {
connect("sqlite3", "dbname=database.db")
deleteTables();
createTables();
}
}
ContactImageProvider {
id: contactImageProvider
database: root.database // I can explicitly get a property
}
}

QML On Item Changed Signal

MyObject
Item {
property int current: 0
}
Can this be configured to emit a signal such that the following works?
Item {
property variant myObj: MyObject {}
onMyObjChanged: doThis()
...
}
cmannet85 has answered your question: it's not possible. Perhaps you could post more code so we can suggest alternative approaches.
In terms of a solution using the information you've provided, you should expose signals that client code should connect to in order to know when the object has changed. Since you said the current property is all that matters, and it already has a change signal, you can use Connections:
Connections {
target: myObj
onCurrentChanged: doThis()
}
Or connect to the signal manually:
Component.onCompleted: {
myObj.onCurrentChanged.connect(doThis);
}
function doThis() {
// ...
}

How to connect a JavaScript function to a property signal?

I'm new to Qml and having some trouble connecting a javascript handler to a property's signal. I have a C++ object with a property and signal.
class CppObject : public QObject
{
Q_OBJECT
Q_PROPERTY(QVariant value READ getValue WRITE setValue NOTIFY valueChanged)
signals:
void valueChanged(const QVariant &);
};
The objects are created through a C++ factory method and I'm able to bind the values
and changes to Qml properties. This all works.
property CppObject obj: cppProxy.PropertyFactory("foo");
Text
{
x: 100;
y: 100;
text: parent.obj.value;
}
For some properties, I'd like to connect the valueChanged signal to a javascript function.
I've been up and down through the Qml documentation and have tried a bunch of stuff without
any luck. I figured something like this should work, but doesn't
function objEventHandler()
{
console.log('objEventHandler() ran')
}
Component.onCompleted:
{
obj.value.valueChanged.connect(objEventHandler);
}
What is the best way to do this?
You can also connect as you've tried in your example, but the form is:
Component.onCompleted:
{
obj.valueChanged.connect(objEventHandler);
}
The signal is not a property of the 'value' object, but of 'obj'.
It's simple using the connections object.
Connections
{
target: obj;
onValueChanged: console.log('changed');
}

Resources