Part of my code are two C++ classes 'ClassA' and 'ClassB' which are both inherited from QObject.
And in some of its methods ClassB needs to syncronously request data stored in ClassA.
ClassA <----- request data ----- ClassB
Is there Qt API similar to signals/slots which can be used for it?
There are two possible options which I can think of but I am not sure
if they are architecturally correct:
1) To define Q_INVOKABLE function in ClassA which would return the needed data as its return value and to call it in ClassB.
But I am not sure if Q_INVOKABLE can be used for purposes other than C++/QML bonding and how to register it properly in other cases.
2) To create regular signal/slot pair in ClassB/ClassA respectively.
signal emitted in ClassB would be used to request the data from ClassA and would have a pointer as its input arg which would point to where store the data.
And slot in ClassA would write the data to this pointer.
void ClassA::slot(type *ptr)
{
// write data to ptr
}
void ClassB::signal(type *ptr)
Sounds like you want dependency injection. That's a fancy word for simply giving reference of class A to class B, probably as a constructor parameter.
Use QPointer<ClassA> if you can decide it's ClassA when writing the source code. Then just call any methods of ClassA as needed.
If you can't lock the exact class, just know it will be QObject, then use QPointer<QObject> and use Qt properties or invokable methods (Q_INVOKABLE or just a slot with a return value) to request what you want.
As an alternative, if ClassB instance can own an instance of ClassA, just give a pointer to ClassA instance to B, and then make B set itself as parent of A. Then it'll be automatically deleted by the destructor (the usual Qt way of QObject ownership).
Related
I have a startup class as such which sets up a SystemControllerin the construct:
m_systemController(new SystemController(this,
Provider::getSettingsAsSingleton())),
Essentially this satisfies:
public:
explicit SystemController(QObject *parent,
Settings& config);
I've recently though wanted to use this class in a threaded class, which doesn't like me passing me the SystemController as the threaded class doesn't have a parent. I tried passing it as such:
public:
explicit DataTestWorker(QObject *parent=0);//,
//SystemController &sysCtrl); //Obviously in my setup, it would complain about this
Where the DataTestWorker class is in fact the threaded class, initialised in a DataTest class. The reason I want to pass the memory location of the SystemController, is the Controller class has important data already setup in the class, which I wish to access without having to run all my initialisation methods within it again.
Is there a way to somehow pass it some sort of "shared" pointer - in which not only this class - but other classes can access it. The only way around this I can think of is I could use signals and slots between the DataTest and the DataTestWorker class to manipulate the values in the SystemController, but this would be long and verbose.
Any ideas? If you need anymore information, just ask.
Is It Possible to Use a Shared Pointer for the Parent of a QObject?
No. There is no shared pointer which is a subclass of QObject. And I don't see why it will make sense.
The reason I want to pass the memory location of the SystemController,
is the Controller class has important data already setup in the class,
which I wish to access without having to run all my initialisation
methods within it again.
Why don't you separate the notion of SystemController settings into another POD class\struct. Then you can have either
class SystemController : public QObject, public SystemSettings
or
class SystemController : public QObject
{
SystemSettings m_settings;
SystemSettings systemSettings() {m_settings};
}
and play around with the settings as you wish.
You can shape your SystemController to Singleton and put QMutex guards to access SystemController's private data used in concurrent threads.
To elaborate on the ambiguous title, I'd like to roughly know how the meta system works dynamically.
When working with slots/property accessors in a static context the calls are probably inlined, after all if it is possible why not??
But what about dynamic scenarios and querying for indices? How is the meta object implemented? Is the offset one of a pointer in a virtual table? Or maybe Qt creates its own vtable instead the one used by the class virtual methods? In this case, are virtual property methods duplicated in both the class "native" vtable as well as the hypothetical extra one created for the static meta object? Are the actual calls technically virtual?
I am not interest in intricate details, more like the overall concept.
First of all, there is no such thing as a "virtual table" when portable C++ is concerned. It's an implementation detail, hidden by the compiler. There's no way to portably access its internals (the implementation's data structure), only its semantics (the functionality it offers).
Secondly, you don't say what you mean by a "call". Assume we have
class BaseObject : public QObject {
Q_OBJECT
public:
Q_SIGNAL void mySignal();
}
class MyObject : public BaseObject {
Q_OBJECT
public:
Q_SLOT void mySlot();
};
MyObject myObject;
There are multiple ways of invoking mySlot.
Calling it directly:
myObject.mySlot("yay!")
This is no different than calling any other method - just because it's a slot, doesn't make it special from C++'s point of view. If it happens to be a virtual method, it's a virtual method call, with any overheads this entails on a given platform.
By using the virtual qt_metacall method with the method index:
myObject.qt_metacall(QMetaObject::InvokeMetaMethod, 4, nullptr);
The implementation of qt_metacall is generated by moc. The qt_metacall is where the method indices get defined. Internally, qt_metacall calls itself recursively all the way into QObject::qt_metacall.
Each implementation checks if the method index is less than the number of metamethods on this class. The constant data record with this information is generated by moc. For example, QObject has three metamethods - the two signals and one slot. If the index is too larger than 2, it is decremented by the number of metamethods and returned to the next derived class's qt_metacall.
When QObject::qt_metacall returns into BaseObject::qt_metacall, the index has been decremented by 3, and is now one (4-3 = 1). Since BaseObject has only one metamethod (index 0), this index is decremented by one and returned.
When BaseObject::qt_metacall returns into MyObject::qt_metacall, the index has been decremented by (3+1=4), and is now zero (0). That's the local index of the lone mySlot, and call is handled by passing the index to MyObject::qt_static_metacall.
By using the static qt_static_metacall (it's a private method, though):
MyObject::qt_static_metacall(&myObject, QMetaObject::InvokeMethod, 0, nullptr);
The qt_static_metacall is a static method that implements the actual call. It simply switches on the local, 0-based index, and calls the method, passing any arguments it needs. The pointers-to-arguments are passed in the last argument - here it's simply a nullptr since there are no arguments. This is plain boring C++ code, no magic there.
We use the knowledge that the method with index 4 is really a method on MyObject (and not, say, QObject or BaseObject). Since all the base classes together use up 4 indices, we adjust the method index down by the same amount - to zero (4-4 = 0).
So, if you know what concrete class implements the method index, you can call the static method directly without using the recursive virtual qt_metacall. This lookup is performed by QObject::connect when the connection is being set up. The connection's destination is stored as a local method index and a pointer to the qt_static_metacall method of the class that has given method. This saves the cost of recursion of qt_metacall when the slot is invoked by the connected signal.
By using QMetaObject::invokeMethod:
QMetaObject::invokeMethod(&myObject, "mySlot");
This performs all the same lookups as QObject::connect does, but instead of setting up a connection, it executes the call right away. Again, it will end in MyObject::qt_static_metacall.
By using QMetaMethod::invoke:
QMetaMethod method = myObject.metaObject()->method(
myObject.metaObject->indexOfSlot("mySlot()"));
method.invoke(myObject);
The QMetaObject caches the looked-up pointer to MyObject::qt_static_metacall as well as the local method index 0. Thus the invoke call has less overhead than the one from QMetaObject.
I am creating a mixin between two classes using the boost::enable_shared_from_this template. So I am adding a new functionality to this class:
class MyOldClass :
public Connection,
public boost::enable_shared_from_this<MyOldClass>
{ ... };
I did use this before with a normal class (not a QtObject, just a C++ plain class) and everything works.
But now I am doing the same with a QMainWindow and it basically crash:
class MainWindow :
public QMainWindow,
public Connection,
public boost::enable_shared_from_this<MainWindow>
{ Q_OBJECT ... };
Is it possible that there is any problem doing this with a QObject? Not sure why this is happening.
Thank you.
You mentioned in the comments that you don't create a shared_ptr before you call shared_from_this(). But that's the problem. x.shared_from_this() only works once a shared_ptr to x exists. If you never create one, you're violating a precondition of shared_from_this(), so your program has undefined behaviour.
shared_from_this() only serves to retrieve a pointer sharing ownership with existing shared pointers; it cannot be used to create the first one.
Ok folks, it has been my fault but the answer could help to someone:
As Angew said it is necessary to create the first instance of MainWindow using a shared_ptr (I didn't understand your question the first time).
I was doing this but I was using the std::shared_ptr implementation instead of the boost::shared_ptr one. Mixing both was producing this results.
It works now but as Angew said one has to be very careful using shared_ptr's with the Qt ownership scheme.
The inheritance order specified in the MainWindow declaration is the only one valid. As Angew said: "When inheriting from QObject or a class derived from it, QObject (or that derived class) must be the first one in the base class list. So that won't work"
Thank you
I have a subclass of QTreeWidget, and I want to do some operation such as
class MyTree(QTreeWidget):
def mouseMoveEvent(self, event):
super(MyTreeWidget,self).mouseMoveEvent(event)
event = QMouseEvent(event)
It seems that MyTree type has changed to MyTree, I cannot call QTreeWidget method itemAt unless I use super key word like this:
super(MyTreeWidget,self).itemAt(event.globalPos())
Is there a similar method to qobject_cast in PyQt? I know qobject_cast exists in Qt.
There is no equivalent of qobject_cast in PyQt. If you wish to access an overridden superclass method, you must use super.
In C++, you can have a variable declared as a pointer to one type QObject * when it actually points to an object of a derived type. For example:
QObject *obj = new QWidget;
I don't know C++ well enough to say whether methods are determined at compile time or run time. In other words, if you then have
obj->someQObjectMethodOverriddenInQWidget(...);
then I'm not sure whether this will call the QObject or QWidget method. (I would guess that it would be the QObject method; it seems you want to use qobject_cast to cast an object to the superclass in order to call overridden superclass methods, and if this didn't happen you wouldn't be wanting to use qobject_cast.)
On the other hand, Python has no type information available at compile time; it relies solely on the run-time type of an object to determine which method to call. If you have overridden a method in a subclass, and you want to call the overridden method from the superclass, you must use super. On the other hand, if MyTree does not override itemAt, you should just be able to call self.itemAt(...), as it will inherit itemAt from its superclass.
I know that Qobjects are supposed to be identities not values eg you cannot copy them and by default the copy constructor and assignment are disabled as explained in qt documentation. But is it possible to create a new QObject from an existing one using a clone method? Would this be a logic error ?
If I say
QObject b;
QObject a;
b.cloneFrom(a);
or
QObject a = new QOBject();
QObject b = new QOBject();
b->cloneFrom(a);
and the clone method copies stuff like members etc would this be wrong?
And if this is ok can I write my own copy constructor and assignment operator that does just that?
Note: I actually want to try this with classes that inherit qobject.
in my opinion cloning QObjects is almost always semantically broken and leads to unwanted side-effects, due to them having an "identity" as you already said. Therefore, cloning breaks all the assumptions one has about QObjects, like their signal/slot connections and dynamic properties. You should consider if the objects to clone really need to be QObjects, or if the "value-part" you want to have cloned could be factored out.
And if at all, cloning makes only sense for your specific subclasses of QObjects, not for QObjects themselves (which have no real "value-like" properties).
also, A; B; A.cloneFrom( B ) looks broken, as it doesn't work if B is instance of a subclass of B instead of B itself.
Clone should be done via a virtual B* B::clone() const I'd say.
I think that the best practice in this case to create class with the data you want to copy between QObjects. This class should not be derived from QObject or any class derived from QObject. And this class will be "value container". In this case you should be able to solve your problem in really good way.
One more tip: for this class you can use implicit data sharing with copy on write to reduce overhead of unnecessary copying: http://doc.qt.io/qt-5/implicit-sharing.html