I have written, qmlRegisterType<QTextToSpeech>("com.company.Speech" , 1, 0, "TextToSpeech");
But I know, I can not access, public methods of QTextToSpeech class, since API is not known to the meta object compiler. Can Some one help me to resolve this issue. I mean is it OK to use below approach ?
class TextToSpeech: public QTextToSpeech
{
Q_OBJECT
Q_INVOKABLE void stop(){ QTextToSpeech::stop();}
};
I am not sure, whether above approach is optimum or not. Since every public method explicitly need to written, Does Qt provides any other quick solution( script/any ), so that existing Qt class can directly export to qml with ease registration ?
Related
We are in the process of converting C# code to C++, but we need to do so in phases. I am at a point now where I need to instantiate several native objects from within managed code. These native objects I cannot change, and their declaration looks like this:
public class NativeA();
public class NativeB(std::shared_ptr<NativeA> obj);
Both NativeA and NativeB need to be instantiated from managed code as:
void main() {
ManagedA ObjectA = gcnew ManagedA();
ManagedB ObjectB = gcnew ManagedB(ObjectA);
}
The problem comes in with getting the shared_ptr of NativeA in the constructor of NativeB. Niether NativeA nor NativeB will be manipulated in managed code, they just need to be instantiated. Ideally, something like this:
public ref class ManagedA {
public:
ManagedA() { _object = new NativeA(); }
~ManagedA() { delete _object; }
NativeA * Get() { return _object; }
private:
NativeA *_object;
};
public ref class ManagedB {
public:
ManagedB(ManagedA^ objectA ) {
_object = new NativeB(std::make_shared<NativeA>(*objectA->Get());
}
~ManagedB() { delete _object; }
private:
NativeB *_object;
};
But, this is not allowed in c++/cli because native types are declared as private. Defining #pragma make_public(NativeA) does not solve this either.
My intent is not to work with the native objects in managed code, they just need to be instantiated, so I really don't care about trying to marshal the native pointers and deal with .NET GC if I don't have to, and I don't want to perform a copy. I just want to wrap the classes in order to pass them around.
Is there a clean and simple way to do this?
It appears that the answer was not due to a syntax or usage problem. The two managed objects were in different DLLs and could not be passed across them via .NET. Once the code was compiled in the same project, the issue was resolved.
Although the error message indicated the problem was an accessibility issue in VS 2015, and because it reported it during the link phase, I suspect the cause was because the linker would not have known about the implementation of the NativeA in NativeB without declaring an extern. Being wrapped in CLR, it surfaced as a different issue.
I have a Qt OpenGL application that uses a QOpenGLWidget to render content. In another class (let's call it Resources), I want to create OpenGL resources like VBOs, VAO, shader programs, etc. for this widget. This creation method is not called by the QOpenGLWidget, but by an external caller.
For some reason, there exist two OpenGL contexts in my application (one is probably used for GUI stuff and the other for the QOpenGLWidget). Hence, when the resource creation method is called, I cannot be sure that the correct context is active. So when I call
QOpenGLVertexArrayObject vao;
vao.create();
in the Resources class, I cannot be sure that this VAO is created on the right context. The Resources class does not have access to the widget. Thus, context.makeCurrent() cannot be called (because I do not know the surface).
Is there a direct way to specify the context, on which the resources should be created? Storing the surface in the Resources file (along with the context) seems very untidy.
Apparently, there is no way to create resources on a specific context. I worked around this issue with the following structure:
I created an interface OpenGLContextProvider, which is very simple:
class OpenGLContextProvider
{
public:
virtual void MakeOpenGLContextCurrent() = 0;
};
The OpenGL widget implements this interface:
class GLView : public QOpenGLWidget, public OpenGLContextProvider
{
//...
};
void GLView::MakeOpenGLContextCurrent()
{
makeCurrent();
}
As such, the OpenGLContextProvider (i.e. the OpenGL widget) is injected into the Resource object's constructor. Before it needs the context, it calls the according method:
void Resources::LoadSomeData()
{
//Load data...
//Create OpenGL resources
ctx->MakeOpenGLContextCurrent(); //ctx is of type OpenGLContextProvider*
vao.create(); //is now on the correct context
//etc.
}
I have written a customer Class (inheriting from QObject) in C++ and registered it's type successfully with QML. Currently I'm creating objects of this class statically in C++ and storing a pointer to them in a Model which implements QAbstractListModel. In QML in I can access the objects perfectly as items of the Model.
The customObject is a non-visual object.
I'm visualising in another part of the GUI application (QML) the objects in a ListView with a delegate.
However now I would like to create objects from my custom Class dynamically in QML and store them also in the Model. This is where I'm struggling. I hoped I could create a customObject like this:
import com.myProject.myCustomStuff 1.0
...
Button{
id: createObjBtn
text: "create new CustomObj"
onClicked:{
var obj = MyCustomObj;
myObjectManager.addObj(obj); // object holding the implemented QAbstactListModel
console.log(typeof(obj)); // returns [Object object]
console.log(Qt.isQtObject(obj)) // returns false
}
}
I would appreciate your thoughts. Maybe someone knows a way to do this correctly?
Thanks!
Update 1
As requested by Simon-Warta, here is the Constructor implementation of MyCustomObj.
MyCustomObj.cpp
MyCustomObj::MyCustomObj(QObject *parent) : QObject(parent)
{
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
}
You are confusing the functionality intent of the classes. The QAbstractListModel is intended as a wrapper around a container, yes, you could put the container inside the QAbstractListModel derived class, but you don't really have to, the container can be just about any C++ class, not necessarily even QObject derived, it can be just a QVector<Something> that you can reach from the model via a pointer. Which is good for cases where you have many objects, and not all need to have models at all the time, since those models are pretty heavy.
You don't really need to concern yourself with the ownership, leave that at the C++ side, the same goes for the actual object creation, have a slot called that adds the new object to the container while also using the model's beginInsertRows() and endInsertRows() so that any views will be notified to update efficiently, the new object should also be created in that slot, you can pass any data needed for it from QML, just make sure all data is registered with the Qt meta system so it can work with QVariant for QML-C++ interop.
So it should be something like:
myObjectManager.create(/* any needed data goes here */)
And create() passes eventual data to the C++ side, where you create the object, call beginInsertRows(), add the object to the model's underlying storage, then call endInsertRows() and you are done.
I'd prefer to keep the ownership in the C++ side (and I don't mean explicitly), where I have control over it. Qt kind of sucks in a big way when dealing with object ownership shared between C++ and QML. Ideally, there should be a single shared pointer class that will work across both C++ and QML, so the object is deleted once all reference to it are gone. But that is just not the "Qt way" - the Qt shared pointers do not work with QML, nor do the standard C++ shared pointers, there is actually an entirely different shared reference class for QML, which is not even part of the public API IIRC, very ugly and shortsighted design that only widens the gap between C++ and QML and the associated inconvenience factor.
I don't know if this is the shortest way but this should do for you. I am starting with the basics for those other up-voters.
MyCustomObj.h
class MyCustomObj : public QObject
{
Q_OBJECT
public:
// ...
Q_INVOKABLE void funfunction();
MyCustomObj.cpp
void MyCustomObj::funfunction()
{
qDebug("Fun with QML");
}
main.cpp
qmlRegisterType<MyCustomObj>("com.myProject.myCustomStuff", 1, 0, "MyCustomObj");
app.qml
import com.myProject.myCustomStuff 1.0
ApplicationWindow {
id: mainWindow
Component {
id: myComponent
MyCustomObj {
}
}
Component.onCompleted: {
var obj = myComponent.createObject(mainWindow)
if (!obj) console.error("Error creating object")
console.log(typeof(obj))
console.log(Qt.isQtObject(obj))
obj.funfunction()
}
}
createObject optionally takes properties to be passed to the component.
Storing
Since you are responsible for deleting the objects now, I'd recommend to use shared pointers, such that the objects get destroyed when the List is destroyed.
Your implementation of QAbstactListModel, let's call it MyModel has an adder function like that:
#include <memory> // for std::shared_ptr
class MyModel : public QAbstractListModel
{
Q_OBJECT
public:
// ..
Q_INVOKABLE addObj(MyCustomObj* obj)
{
objectlist_.append(std::shared_ptr<MyCustomObj>(obj));
}
private:
QList<std::shared_ptr<MyCustomObj>> objectlist_
}
I use observer-observable pattern in my program. Everything worked before I had to change the code a little. If to be exact I changed the inheritance of IObserver class - right now it inherits QObject:
class IObserver : public QObject
{
...
I did it because of only one thing - I need deleteLater() method to be used in an observer, so I would be able to call implementation of virtual function deinitialization() of IObserver. Thus I could standardize every IObserver message handler.
The problem is, I already inherited QObject (indirectly) in some Observer classes. Like MainForm or AboutDialog. Everything is going fine until I try to call "connect" method in AboutDialog class.
What can I do? I really need this deleteLater() method since I can't use "delete this" in IObserver code - this will call IObserver destructor, not the MainForm or Storage classes for instance.
Thank you.
I really need this deleteLater() method since I can't use "delete this" in IObserver code - this will call IObserver destructor, not the MainForm or Storage classes for instance.
If you make your destructor virtual (and you should!) it will call the derived destructor just fine. But a problem is that destructing a object while it is handling some signal/slot might cause problems with the event loop. You would have to be very careful with delete this anyway.
The problem is, I already inherited QObject (indirectly) in some Observer classes.
One way you could implement this, not sure if the best thought:
template <typename Derived>
class IObserver
{
// Just to be sure: (C++11)
static_assert(is_base_of<Derived, QObject>::value,
"must inherit from QObject when using IObserver");
void deleteMe()
{
QObject* thisObject = dynamic_cast<QObject*>(this);
// no need for check if thisObject equals null. static assert does this.
thisObject->deleteLater();
}
};
class MainForm : public IObserver<MainForm>, public QMainWindow
{
// ...
};
I believe this pattern is called static polymorphism.
Abandon inheritance of QObject for IObserver. Instead of that add such method to interface.
class IObserver : public QObject {
public:
QObject *object() const = 0;
...
Then if implementation of interface inherits the QObject you will return this pointer from object() method. If implementation of interface doesn't inherit QObject you can simply return pointer to some simple QObject which will handle destruction of this object.
Then you can simply connect deleteLater for object returned by this method.
Off topic
Use of interfaces for observing in Qt usually is obsolete, slots and signals do this job perfectly and this is more flexible approach.
As we all know, Q_OBJECTs are instances and are not copyable.
Is there any kind of syntactic sugar to copy all static and dynamic properties of an arbitrary QObject derived class?
It seems such a nobrainer, but I can't find any reference to such - obviously implementing one myself should be quite trivial - loop over metaObject(), loop over dynamicPropertyNames(), set accordingly.
You could implement a copy helper class as follows.
/** Enable QObjects to be explicitly copyable by copying property values. */
template<class T>
class QObjectCopyHelper<T>
{
protected:
explicit QObjectCopyHelper(T *client) : m_client(client) {}
public:
T *clone(QObject *parent = 0) {
T *copy = new T(parent);
// loop over and copy properties from m_client to copy
// (both from T::staticMetaObject and dynamic ones)
return copy;
}
private:
T *m_client; // <-- I think we need this, but I might be wrong
};
Then you can use this in any QObject subclass with very low work needed to be done:
class MyClass : public QObject, public QObjectCopyHelper<MyClass>
{
Q_OBJECT
...
};
However, this still needs clone() to be called (the ugly "Java-style"). So we can additionally define a copy constructor just calling clone() and you also might think of a assign() method called within the assignment operator.
Please note that this really copies the properties only! There are a lot of other things being tracked in QObject, like the current connections. They explicitly forbid copying QObjects because it would be very difficult to define rules on how this should be done, and these rules would be the correct ones for some use cases only, while in others you want other rules...
A solution is discussed here, where they take the loop-over-the-properties approach. There seems to be no "syntactic sugar" here.