To access QML component in C++ backend - qt

I have a qml file with Rectangle. I would like to trigger the onClicked( ) from C++ back-end.
So, How can I get access of QML component reference in C++/Qt backend?

You should use QObject::findChild() to locate the object, and simply invoke the signal as you would a nominal method.
But there is a catch, as QQuickRectangle itself is a private class, so it is not directly available for use in the C++ API. Also, it doesn't really have a clicked() signal, not unless you implemented one yourself. And if you did, it won't be part of the C++ interface.
Also, there is no onClicked() signal, the signal is clicked() and onClicked: is the handler hook.
However, you can still emit it using the Qt meta system, just use:
QObject * object = engine.rootObjects().at(0)->findChild<QObject *>("yourObjectName");
if (object) QMetaObject::invokeMethod(object, "clicked");
It will work even if the signal is implemented on the QML side, it will work even without casting to the concrete C++ type.
Now, if your object is not directly in the root object tree, you will not be able to find it and will have no choice but to pass a reference to it from the QML side to a C++ slot or invokable function.

Related

Are "public slots:" sections still necessary in Qt5?

A simple question regarding the new signal/slot syntax in Qt5:
Are there still benefits for a Q_OBJECT-derived class to have public slots: sections declared?
Note: With the new syntax you're able to connect a signal to any public function of a class or directly implement a C++11 lambda (which can also call some member functions itself).
Qt's new signal/slot syntax
While the answers by vahancho and TheDarkKnight are valid: slots is not required for connections, but it makes the intent clearer and allows introspection. I think I should list some use cases where you do need slots.
First please note that you can use slots, Q_SLOTS, Q_SLOT or Q_INVOKABLE to make a function known to the meta object (introspection) system. Q_INVOKABLE has the advantage that it can be used on constructors.
And here are the use cases in no particular order:
Make your code works with Qt 4. Even if Qt 4 is not maintained I think some big company are still using it and it is fairly easy to make a library works with Qt 5 and Qt 4.
Make the function available in QML (and Qt Quick)
Make the function available in javascript (Qt Script, Qt WebEngine, etc.)
Make the function callable with QMetaObject::invokeMethod(). An overload that accepts functors will be available in Qt 5.10.
Make use of QMetaObject::connectSlotsByName(). Note that this function should not be used as it can be affected by object name collisions, but it is still the way the Qt widget designer connects the slots it creates.
Make your class instantiatable with QMetaObject::newInstance().
And every other use case that requires run-time introspection
you're able to connect a signal to any public function of a class or directly implement a C++11 lambda
Whilst this was made available in Qt 5, which allows for compile-time verification of the slot, as opposed to when using the SIGNAL and SLOT macros, it is no longer a requirement to declare a function as a slot to connect to it.
However, for clarity I still do, as it makes the intention of a class clearer for usage, when others come to using the class.
For example:
class Foo : public QObject
{
public:
Foo();
public slots:
void AddData();
private:
void CalculateStuff();
};
Just by looking at the class, we can assume that the function AddData is designed to be called via a signal; perhaps it executes on a separate thread.
public slots: etc. declarations still needed for moc introspection if you are going to use the "old" connection style. With the new syntax this declarations do not make any sense, because, as you also noticed, "slots" are called directly by function pointers. "Slots" may even be a non class member functions as well.
However, you still need to declare your signals under signals: section of your class declaration.
They're still needed for Qml, so that you can connect to C++ slots. However, if you want to call a C++ QObject member function, you can just declare it as Q_INVOKABLE. You don't need to make it a slot. Although using slots: might be more readable compared to using Q_INVOKABLE. Up to you.
They're also needed if you want Designer to see them. Designer has a "signal/slot" editor, and it will not list functions that are not in the slots: section. However, Designer still uses the old string-based syntax for signals and slots, so I wouldn't recommend using its signal/slot editor.

Signal to Slot in QT Creator, where is connect() function?

In QT Creator, design mode, I right-click on a widget and select "Go to slot" and it creates a slot function for one of the widget's signals.
I would have thought that this would have generated a connect() function to create this connection, however, I can't find anything like that in any of the source code.
Where is the actual code that connects the widget's signal to the slot function?
thanks
If you're using QtCreator's Designer, one of the outputs from this is a .ui file
Qt Designer ui files are an XML representation of your form's widget tree, and are processed by uic, the "User Interface Compiler"
One of the features provided by Qt's ui format is AutoConnect.
uic automatically generates code in the form's setupUi() function to connect your signals and slots.
The way it works is as follows:
Your slots must conform to the following format:
void on_<object-name>_<signal-name>(<signal-parameters>);
where object-name is the name of the object which emits the signal this slot is for.
Later, uic then generates code which calls QMetaObject::connectSlotsByName(this);
Using Qt's reflection system, the QObject which has objectName()=object-name is found, and it's signal is connected to your slot.

Can I pass "this" to a Q_Slot?

I have an application with many windows (QWidgets).
I didn't save a list of open windows, though, so everytime I want to close a window, I have to retrieve it.
Particularly, each of these windows is called here SubWindow.
Every SubWindow class contains a layout with a MultiEditor *sEditors, which has a menu with an action that closes the current window.
Every SubWindow is created within the MainWindow.
I have two plans.
1) destroying the SubWindow from within itself, by adding in the SubWindow constructor
connect(sEditors, SIGNAL(closeWindow()),
this, closeWindow()));
or
2) destroying the SubWindow from within the MainWindow class, by adding in the SubWindow constructor
connect(sEditors, SIGNAL(closeWindow()),
main, SLOT(closeWindow(this)));
About 1), I don't understand how I can close and destroy a QWidget from within itself (delete this; didn't seem to work, but I can try again).
About 2) my SLOT(closeWindow(this)) doesn't seem to be triggered, so I am wondering if I can pass "this" as an argument.
Ad 1) You can use QObject::deleteLater(). This will destroy the object in the next event loop cycle, and is specifically create for situations like this
Ad 2) You cannot pass actual arguments as parameters in signal-slot connections.
You can however find out who has emitted the signal by using the sender() function in the slot. In your case, that would be the sEditors object.
Other options:
3) You can use a QSignalMapper to map signals from your editors to the Subwindows.
4) (Using Qt5 / C++11) You can use a lambda connection in your Subwindows:
connect(sEditors, SIGNAL(closeWindow()), [this] () {this->closeWindow();});
Can I pass this to a Qt slot?
A slot is a non-static method, so it already has access to this. The this you refer to is the third argument to QObject::connect. In Qt 4 syntax, you're free to omit the third argument - it defaults to this. In Qt 5 syntax, you must be explicit about it, though.
I don't understand how I can close and destroy a QWidget from within itself
To delete any QObject from within itself, use QObject::deleteLater(). Recall that a QWidget is-a QObject in terms of LSP.
my SLOT(closeWindow(this)) doesn't seem to be triggered
There's no such slot (give us a link to its documentation: you can't), and your slot signature is also invalid because the only things within the parentheses in the slot signature can be types, and this is not a type: SLOT(slotName(TYPE_LIST_HERE)), e.g. SLOT(mySlot(int,QString)).
To close a widget, use its close() slot:
connect(sEditors, SIGNAL(closeWindow()), this, SLOT(close());
Yet, by using Qt 4 connect syntax, you're leaving coding mistakes to be detected at runtime - and then if you don't pay attention to the debug output at runtime, you'll miss it. It's thus much better to use the new (Qt 5) connect syntax, and let the compiler detect errors for you:
connect(sEditors, &MultiEditor::closeWindow, this, &QWidget::close);
Alas, there's no need to tightly couple the object that sends closeWindow to SubWindow - at least not within the SubWindow::SubWindow(). Instead, you can connect at the place where you create the editor.
To delete a widget when it gets closed, simply set the Qt::WA_DeleteOnClose attribute on it and let Qt do it for you. No need to explicitly call deleteLater etc.
You might factor all of it into a factory method:
template <class T> T* SubWindow::makeEditor() {
auto sub = new T{this};
sub->setAttribute(Qt::WA_DeleteOnClose);
connect(sEditor, &MultiEditor::closeWindow, sub, &QWidget::close);
return sub;
}
MainWindow::MainWindow(/*...*/) : /*...*/ {
makeEditor<EditorType1>();
makeEditor<EditorType2>();
/*...*/
}

SIGNAL & SLOT macros in Qt : what do they do?

I'm a beginner in Qt and trying to understand the SIGNAL and SLOT macros. When I'm learning to use the connect method to bind the signal and slot, I found the tutorials on Qt's official reference page uses:
connect(obj1, SIGNAL(signal(int)), obj2, SLOT(slot()))
However, this also works very well:
connect(obj1, &Obj1::signal, obj2, &Obj2::slot)
So what exactly do the macros SIGNAL and SLOT do? Do they just look for the signal in the class the object belongs to and return the address of it?
Then why do most programmers use these macros instead of using &Obj1::signal since the latter appears to be simpler and you don't need to change the code if the parameters of the signal function change?
The use of the SIGNAL and SLOT macros used to be the only way to make connections, before Qt 5. The connection is made at runtime and require signal and slots to be marked in the header. For example:
Class MyClass : public QObject
{
Q_OBJECT
signals:
void Signal();
slots:
void ASlotFunction();
};
To avoid repetition, the way in which it works is described in the QT 4 documentation.
The signal and slot mechanism is part of the C++ extensions that are provided by Qt and make use of the Meta Object Compiler (moc).
This explains why signals and slots use the moc.
The second connect method is much improved as the functions specified can be checked at the time of compilation, not runtime. In addition, by using the address of a function, you can refer to any class function, not just those in the section marked slots:
The documentation was updated for Qt 5.
In addition, there's a good blog post about the Qt 4 connect workings here and Qt 5 here.
Addition to the first answer.
what exactly did the macro SIGNAL and SLOT do
Almost nothing. Look at the qobjectdefs.h:
# define SLOT(a) "1"#a
# define SIGNAL(a) "2"#a
It just adds 1 or 2. It means that next code is valid and works as expected:
QObject *obj = new QObject;
connect(obj,"2objectNameChanged(QString)",this,"1show()");//suppose this is a pointer to a QDialog subclass
obj->setObjectName("newNAme");
why do most programmers use these macros instead of using like
&Obj1::signal
Because these macros work not only in Qt5.
Because with these macros there is no complexity with overloaded
signals (it can make your code very dirty and it is really not a simple thing)
Because with new syntax you sometimes need to use specific
disconnects
More details here.
To complete TheDarkKnight's answer, it is an excellent practice to refactor legacy code that is using the old Qt 4 SIGNAL and SLOT macros to Qt 5's new syntax using function address.
Suddenly, connection error will appear at compile time instead of at runtime! It's very easy to make a Qt 4 connection error as any spelling mistake will result in such an error. Plus, the name of the function must be the fully qualified name, i.e preceded with the full namespace if any.
Another benefit is the ability to use a lambda for the slot function, which can reduce need of a named function if the slot body is trivial.
These macros just convert their parameters to signal/slot-specific strings. The Differences between String-Based and Functor-Based Connections can be found in the docs. In short:
String-based:
Type checking is done at Run-time
Can connect signals to slots which have more arguments than the signal (using default parameters)
Can connect C++ functions to QML functions
Functor-based:
Type checking is done at Compile-time
Can perform implicit type conversions
Can connect signals to lambda expressions

How to send signals to a qt class from a not qt class?

I created a qt class only to make gui and displayed the data on gui.
i didn't want to freeze the gui that's why i created another non_qt class to perform the operation so i made a object in the gui class of non_qt class and pass the parameter in that and started it in a new thread.
now after completing the operation i want to notify the gui class so it can display the results.
i also want to access the status bar of gui class so when non_qt class is performing the operation it can display some message on gui..
(i tried it with qt class but it didn't work that's why i created non_qt class..with non_qt class threading part is working fine but signal part is not working so i'm not able to notify the gui class).
so please help me out how to send signal to a qt class from a not qt class????
The signal is a concept that only applies to classes that derive from QObject.
If you want to trigger a slot, you don't need a signal. If the receiving object lives in the same thread (and only then), you can call the slot method on the reciving object directly.
For example, given an instance of a GUI object with a slot:
MainWindow * mainWindow;
class MainWindow : public QWidget {
Q_OBJECT
...
Q_SLOT void setStatus(const QString &);
...
};
You can simply do:
// The assert is essential to prevent bad bugs. If it triggers,
// you must use `QMetaObject::invokeMethod` instead.
Q_ASSERT(mainWindow->thread() == QThread::currentThread());
mainWindow->setStatus("Finished");
If the receiving object may live in another thread, or if you don't want to worry about threading issues, then you must use QMetaObject::invokeMethod, as follows:
// This is always safe. No need for asserts.
QMetaObject::invokeMethod(mainWindow, "setStatus",
Q_ARG(QString, "Finished"));
This overload of invokeMethod will correctly choose the connection type depending on whether the receiving object runs in the same thread. If the receiver is in the same thread, the call is a direct call. If it runs in another thread, the call will be converted to a QMetaCallEvent and posted to the receving object. This is thread-safe and doesn't require the receving object's setStatus method to be thread-safe.

Resources