I have a QObject that exists in a QWebFrame javascript environment through the addToJavaScriptWindowObject interface. This QObject has Q_INVOKABLE methods that return more QObject pointers (like a factory) that are used within javascript. Qt automatically turns these QObject pointer into objects that can be invoked in the calling javascript enviornment.
The issue is, I want to have javascript assume ownership of this QObject. The current behavior is that the C++ environment retains ownership.
I've dealt with QScriptEngine directly in the past where the QObject factory object holds a pointer to the QScriptEngine object and creates new objects using QScriptEngine::newQObject with a QScriptEngine::ScriptOwnership argument. This works perfectly. But for the QWebFrame javascript engine, the engine is buried inside of the QWebFrame and inaccessible.
How can I return QObject's to a QWebFrame javascript environment and have javascript assume ownship of that object?
Related
In many cases, QObject::connect() is used as a whole to create a connection of signal and slot, e.g.:
QLabel *label = new QLabel;
QScrollBar *scrollBar = new QScrollBar;
QObject::connect(scrollBar, SIGNAL(valueChanged(int)),
label, SLOT(setNum(int)));
But I have noted there are some cases where the prefix QObject:: can be ommitted. For example, in creating dialogs (with QDialog), connect() can be directly used without the prefix. Is there any other similar situation?
Background: Understanding static member functions
First, let's take a step back and think about static member functions in C++. As an example, suppose we have a class named MyClass, with a static member function named myStaticFunction().
From inside a member function of MyClass (or a subclass of MyClass), there are 3 ways to call the example function:
MyClass::myStaticFunction()
this->myStaticFunction()
myStaticFunction()
However, from outside a member function of MyClass (or a subclass of MyClass), there is only 1 way to call the example function:
MyClass::myStaticFunction()
QObject::connect() is a static member function
For example, in creating dialogs (with QDialog), connect() can be directly used without the prefix.
This has almost nothing to do with creating dialogs at all.
Remember, the QObject class has a static member function called connect()*. Also remember that QDialog is a subclass of QObject.
Therefore, from inside a member function of a QObject subclass, there are 3 ways to call connect():
QObject::connect(...)
this->connect(...)
connect(...)
However, from outside a member function of a QObject subclass (such as in the main() function), there is only 1 way to call connect():
QObject::connect(...)
*To be precise, there are many overloads of connect(), including non-static versions. However, we're only focussing on the static versions.
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.
I have some code that works but I don't understand the meaning of this pattern:
QWindow * window;
if (window = qobject_cast<QWindow *>(root))
window->show();
qobject_cast is Qt's alternative of dynamic_cast for QObject-based classes. root is a pointer to some object. In your case it probably has QObject* or QWidget* type. However, the code expects that it may in fact be a QWindow* object. qobject_cast checks if the object is an instance of QWindow class or any class inherited from it, and returns 0 if that's not the case. If the check is successful, qobject_cast returns QWindow* pointer to the object, and the code can use it to call QWindow-specific methods that are not available through QObject* or QWidget* pointer.
The code translates to the following pseudo-code:
if (root is an instance of `QWindow` set window to that instance)
show that window;
The qobject_cast works exactly like dynamic_cast, but only applies to QObject-derived classes and works even when runtime type information is not available (e.g. for small builds on MSVC, or on some embedded platforms).
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.
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.