I have a feeling this isn't possible with the current API, but I have to ask. Is it possible to query a particular QObject's signal or slot name (from the metaObject) and retrieve all the QObjects and their slot or signals names that are connected to it?
I'm doing this because, in effect, I have a large number of layouts that contain an identical arrangement of widgets, for each layout there an object and each of the layout's widgets control the various properties of it. I want to keep one layout, and connect it's widgets' signal/slots to all the other objects in the same pattern, but in order to do this I need to 'record' all the signal-slot data.
Is it possible?
There is an interesting file in Qt - %Qtdir%/src/corelib/kernel/qobject_p.h, it contains class QObjectPrivate, used by Qt internally.
Use
static QObjectPrivate *get(QObject *o) function to get QObjectPrivate member for your widgets, and try to call its interesting members like
QObjectList receiverList(const char *signal) const; or QObjectList senderList() const;. File is totally undocumented, but it seems to contain exactly what you need...
Related
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 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>();
/*...*/
}
After reading up on the interesting parent-child system of QObject I am wondering how common it is for Qt developers to use this in place of a more traditional container. Assuming memory contiguity is not a requirement, it seems this offers some interesting features.
For example, you could have a QObject and give it children of different types, and then find all children easily based on their types, giving QObject a dynamic heterogenous container-like feature, as opposed to the required homogenous collection of a traditional container.
And QObject naturally manages the memory of its children, which is convenient as well.
Is this a common use of this feature?
QObject::findChildren could be much slower than storing your objects in a normal container like QList because:
It iterates over all children each time. It even searches recursively (but this can be disabled).
It performs runtime type check.
It constructs new QList each time. This can be slow and expensive it there are many objects in result.
All the above it unnecessary if you just use QList<Type*> my_objects. Also in this case:
You can name your collection. QList<QPushButton*> panic_buttons is clearer than findChildren<QPushButton*>().
You can have several collections of objects of the same type.
If you want to make a heterogenous container, you can use QHash<any_type_identifier, QObject*>. It will be faster.
Maybe, findChildren approach may be simplier sometimes. But if you have many objects or a complicated class, you'd better use normal containers. You can still use QObject's memory management with them without any problems.
As #PavelStrakhov states, using QObject::findChildren could be slower. However, one method I use is to combine storing objects in QList as well as having the QObject parent hierarchy. It's based on doing something like this: -
class BaseObject : public QObject
{
Q_OBJECT
public:
static BaseObject* FindObject(unsigned int id); // find object by id
private:
unsigned int m_id;
static unsigned int s_nextId; // next id for a new BaseObject
static QList<QBaseObject*> s_objectsList; // list of all BaseObject-type instances
};
All objects now inherit BaseObject instead of QObject. When a new class is created, the constructor of the BaseObject will set the item's id, increment s_nextId and finally, the object is added to s_objectsList. Finding objects is now a simple matter of searching the static object list.
This may not suit the design of the application that you're developing, but it certainly helped me, especially when using the QGraphicsView / QGraphicsScene system. In that situation, the BaseObject is derived from QGraphicsObject.
Of-course, if you're using a lot of standard widgets, you're less likely to want to create new classes for them all, but it's an option that can suit some designs.
The documentation for QWidget::winId states (among other things) "If a widget is non-native (alien) and winId is invoked on it, that widget will be provided a native handle."
I'm not sure what 'alien' means in that context, but I'm choosing to ignore it for now. :)
So assuming that my widget now has a valid native handle associated with it, can I then pass that native handle to another process and into QWidget::find and get a valid QWidget object back within that second process?
I probably don't need to do too much else to the widget in the second process other than show/hide it and attach it to a parent widget. (It is guaranteed to not be attached to any parent widgets in the first process and never visible in the context of the first process).
If all the above works:
How much control will the second process have over that widget?
Will the first process receive user input events as if it were attached
to the first process's UI, and will the first process be able to update the widget as normal?
James
Let's take a look at Qt sources.
QWidget *QWidget::find(WId id)
{
return QWidgetPrivate::mapper ? QWidgetPrivate::mapper->value(id, 0) : 0;
}
find() can find a widget only if mapper contains it. The mapper is a static QHash<WId, QWidget *> variable. Items are inserted in this hash only in the QWidgetPrivate::setWinId method.
So, if a widget with a WId was created in another process, you can't find it using QWidget::find. This function doesn't use any native OS functions to find widgets.
Also see general description of alien widgets in Qt documentation:
Introduced in Qt 4.4, alien widgets are widgets unknown to the
windowing system. They do not have a native window handle associated
with them. This feature significantly speeds up widget painting,
resizing, and removes flicker.
I'm implementing a Model/View for a tree like structure, and I've decided to try the QStandardItemModel on which I want to wrap on it a specific class, (which I call here "appSpecificClass").
Basically, I want part of that class (like names, or some data), to be shown in the model, and when I change the model (in edit role, or drag and drop), I want that to have consequences on the appSpecificClass (which is, when I change a name that is showing on the model, the name on the object associated with the model's item of the appSpecificClass also changes).
So, I started from subclassing the QStandardItem by a appSpecificItem, which only has a pointer to the appSpecificClass. When I construct the appSpecificItem, the text and icons are called from appSpecificClass and everything works fine.
However, when change data from appSpecificItem, naturally it does not change the appSpecificClass, because so far I didn't found any way of interacting with the appSpecificItem's pointer via overloading a virtual function (or else)
Does anyone knows how to do this/if this is possible? What can I do such that if for instance the signal
QStandardItemModel::itemChanged ( QStandardItem * item )
is emitted, I can change a the appSpecificItem's pointer.
If not, is there any good tutorial about implementing a Model from scratch? I've tried myself some, but it is not an easy task. Ideally I would like a QStandardItemModel like model, but a little more abstraction on it (such that I can put my appSpecificClass on it).