How to expose enum not owned by QObject to QJSEngine? - c++

I am writing scripting wrappers for my SW so I can control my SW via scripts. The purpose of the wrapper classes is to separate the scripting interface from the actual class because I might not want to expose all of the signals and slots of the class. I'm using Qt 5.13 and QJSEngine.
My issue is that based on what I've read and what I've experimented it seems that to be able to expose an enum it needs to be within a class that inherits QObject and is exposed via newQObject()/setProperty(). However I do not want to expose the class Foo in the following example, but I still want to expose the enum Foo::Bar to the scripting environment. How do I do this? Q_ENUM seems to assume the enum is within a QObject and that the QObject is exposed (property) in the scripting environment. Here is a short example what I am doing (I want to be able to call FooWrapper::slot1() from the scripting environment):
class Foo : public QObject
{
Q_OBJECT
public:
Foo(QJSEngine& engine)
{
auto wrapper = new FooWrapper(this, engine);
}
enum class Bar
{
VAL1,
VAL2
};
public slots:
void slot1(Bar bar);
void slot2();
};
class FooWrapper : public QObject
{
Q_OBJECT
public:
Foo(Foo& foo, QJSEngine& engine)
: foo(&foo)
{
QJSValue obj = engine.newQObject(this);
auto gObj = engine.globalObject();
gObj.setProperty("foo", obj);
}
public slots:
void slot1(Bar bar)
{
foo->slot1(bar);
}
private:
Foo* foo;
};

Well this is clearly very late for Dago, the OP (sorry!). In case anyone else runs into this...
One option is same as for QML in general, which is that one can register enums and flags from a namespace. Using Q_ENUM_NS() and Q_FLAG_NS() (for flags the Q_DECLARE_FLAGS() call stays the same, also Q_DECLARE_OPERATORS_FOR_FLAGS() outside the namespace, same as with a class, if you want those).
There is my related answer here:
How to access C++ enum from QML?
But for pure JSEngine usage it is enough to just set the namespace's QMetaObject as a property in the engine... no need for qmlRegisterUncreatableMetaObject... stuff.
So to sum up...
#include <QObject> // required for the macros below
namespace MyNamespace
{
Q_NAMESPACE // required for meta object creation
enum class Bar {
VAL1,
VAL2,
};
Q_ENUM_NS(Bar) // register the enum in meta object data
}
// declare the enum's meta type (required if enum will be used in
// methods/functions exposed to JS.
Q_DECLARE_METATYPE(MyNamespace::Bar)
Later in the QJSEngine initialization routine somewhere...
QJSEngine *jse = new QJSEngine();
...
// Register the namespace's meta object as a property of the global
// object (or any other object's property for that matter).
// The property name doesn't have to match the namespace name.
jse->globalObject().setProperty(
"MyNamespace",
jse->newQMetaObject(&MyNamespace::staticMetaObject)
);
Then in the JS environment the enum is available as a property of the namespace itself.
QJSValue v = jse->evaluate("MyNamespace.VAL2"); // v.toInt() == 1
or in a script...
console.log('>>', MyNamespace.VAL2); // output: >> 1
Another option may be to keep the enums in the class and register the class' QMetaObject as a property of the engine... just do not mark the constructor (or any other static methods) as Q_INVOKABLE.
HTH,
-Max
References:
https://doc.qt.io/qt-6/qjsengine.html#newQMetaObject
https://doc.qt.io/qt-6/qobject.html#Q_NAMESPACE
https://doc.qt.io/qt-6/qobject.html#Q_ENUM_NS
I cannot find a direct reference to registering namespace meta objects as I just described... I assure you it works (and has for quite a few versions).
A vague reference to it here, at the end of the section..
https://doc.qt.io/qt-5/qqmlengine.html#QML_ELEMENT
Another even less relevant (but possibly interesting): https://doc.qt.io/qt-6/qqmlengine.html#QML_EXTENDED_NAMESPACE

Related

QML/QT How to convert object from C++ to QML?

It took me a while, but eventually I managed to convert a JavaScript/QML POJO to a custom object not derived from QObject.
I think it's easier to understand my issue with a working example. So let's start with this:
struct SomeType { /* Just a plain struct that does not derive from QObject! */ };
SomeType FooFactory::convertQMLToSomeType(const QJSValue& val) {
SomeType result = /*... some kind of conversion takes place here ... */
return result;
}
void FooFactory::registerTypes(QQmlEngine& engine) {
QMetaType::registerConverter<QJSValue, SomeType>(FooFactory::convertQMLToSomeType);
}
What this does is it registers a converter for the transformation of QSValue to SomeType. So now, whenever I do something like this in QML
my_prop = { "foo": "some plain javascript object" };
assuming my_prop is exposed like so in the corresponding C++ class:
Q_PROPERTY(SomeType my_prop MEMBER _myProp);
SomeType _myProp;
// Somewhere else outside the class, this is needed for registering the converter
Q_DECLARE_METATYPE(SomeType);
the string is implicitly converted into a SomeType without the need of doing things manually.
..
Great!
But what about the opposite direction of the conversion? I Need QML to deal with strings, not QVariant(SomeType) objects (QT always uses QVariant wrappers internally to store user defined types when dealing with the meta system).
I already tried registering an inverse converter like this:
QMetaType::registerConverter<SomeType, QJSValue>(FooFactory::convertBackToQML);
or this
QMetaType::registerConverter<QVariant(SomeType), QJSValue>(FooFactory::convertBackToQML);
but none of these approaches work. I believe the second line is quite promising, but I wasn't even able to compile that one due to problems with registering the static meta type.
So, how would I solve this? As a short reminder, I am not able to derive SomeType from QObject, and yes, I am aware that this is the most common way to do these kinds of things.
Does anyone have an idea? Or am I barking up the wrong tree? Many thanks in advance!
This may not be what you want, but it might also be your only option. You can create a QObject wrapper class around your struct. Just create properties for whatever values in the struct you want to expose.
class SomeWrapper : public QObject
{
Q_OBJECT
Q_PROPERTY(QString someData READ someData WRITE setSomeData NOTIFY someDataChanged)
public:
explicit SomeWrapper(QObject *parent = nullptr) : QObject(parent) {}
QString someData() { return m_struct.someData; }
void setSomeData(QString data)
{
if (data != m_struct.someData)
{
m_struct.someData = data;
emit someDataChanged();
}
}
signals:
void someDataChanged();
private:
SomeType m_struct;
};
If you want to operate with your structure as with a plain JavaScript object, then another option may be using QVariantMap as a type for your property. Then you could define the needed conversions in getter and setter of your property:
class Whichever : public QObject {
Q_OBJECT
Q_PROPERTY(QVariantMap my_prop READ myProp WRITE setMyProp)
QVariantMap myProp() const {
QVariantMap map;
map["some_field"] = _myProp.someField;
// Fill the other fields as needed.
return map;
}
void setMyProp(const QVariantMap& map) {
_myProp.someField = map["some_field"].toString();
// Fill the other _myProp fields as needed.
}
};
Conversions between QVariantMap and the actual JavaScript objects would be handled by QML engine automatically. Nested JavaScript objects should also be possible by nesting the corresponding QVariantMaps.
Of course, this option makes property declaration not so explicit about which type does it correspond to, and perhaps it will require a bit more boilerplate code if you need to declare multiple properties of this type (you can define and use your own macro for that though if needed). But this is probably one of the easiest ways to achieve what you have described.

Understanding Exposing Attributes of C++ Types to QML

I wanted to write a pretty simple code which looks for a string and then outputs the variable assigned to it.
I wanted to learn more about the communication between C++ and QML. So I thought of using a hash map in C++ and then use those functions in QML to list out the result.
I had lot of errors so I basically tried everything to make it work and now my code works. But can someone help me in understanding what I have done.
I have few doubts
I was not able to access my functions loadItemList() and findcubby() but as soon as I included the Q_OBJECT Macro it started working why ?
I have seen in some codes online that they often use something like explicit Itemlist(QObject *parent = 0); why and what does this mean?
I have defined my Hash map as public variable which I know is not good, can someone show me how would I go about for a private hash map.
Here is my header file
#ifndef ITEMLIST_H
#define ITEMLIST_H
#include <QObject>
#include <QHash>
class Itemlist : public QObject
{
Q_OBJECT
public:
Itemlist();
Q_INVOKABLE int find_cubby(QString);
QHash<QString, int> my_itemlist;
};
Here is cpp file
#include "itemlist.h"
Itemlist::Itemlist()
{
my_itemlist["aaaa"]=1;
my_itemlist["bb"]=1;
my_itemlist["cc"]=1;
my_itemlist["dd"]=1;
my_itemlist["ee"]=2;
my_itemlist["ff"]=2;
my_itemlist["gg"]=3;
my_itemlist["hh"]=3;
my_itemlist["ii"]=3;
}
int Itemlist::find_cubby(QString Name)
{
if(my_itemlist.contains(Name))
{
return my_itemlist.value(Name);
}
else
{
return 4;
}
}
Q_OBJECT is necessary as it serves as a marker for the moc code generator to create runtime introspection data for the class. Features such as properties or Q_INVOKABLE depend on that mechanism.
explicit is a C++ key word that marks a constructor as not available for implicit type conversions. Generally, constructors that can be called with a single argument can be used by the compiler to convert between the argument type and the class of that constructor.
E.g.
class Foo
{
public:
Foo(int i) {}
};
void doSomething(Foo f) {}
doSomething(5);
The compiler has an integer, 5, and needs a Foo object. There is a constructor for Foo that takes an int, so it can use it for an automatic type conversion.
explicit Foo(int i) {} removes that option, so the compiler will exit with an error, saying that it can't find a doSomething(int) function.
Use a private: section in your class just like you currently do with public:

Qt access D-Pointer of inherited Class

I am trying to understand how the whole d-pointer thing i working. I got most parts but I am currently facing a problem:
Like the guy here Dpointer inheritance i want to inherit a class using d-pointers (infact it is QProcess).
Since the function to access the d-pointer is private i can not access it with simple inheritance. My idea is to again use the Q_DECLARE_PRIVATE macro to get the function and to access it. Can this work? Before I try out I want some hints since I dont know if this can even work.
(I need this to avoid the whole licensing issues.)
MyProcess.h
#ifndef MYPROCESS_H
#define MYPROCESS_H
class QProcessPrivate;
class MyProcess : public QProcess {
public:
MyProcess(QObject *parent = 0);
protected:
Q_DECLARE_PRIVATE(QProcessPrivate);
};
#endif /* WIDGET_H */
MyProcess.cpp
#include "myprocess.h"
MyProcess::MyProcess(QObject *parent = 0)
: QProcess(parent) {
}
MyProcess::setPid(Q_PID pid) {
Q_D(const QProcess);
d->pid = pid;
}
First of all, let's cover the basics. IANAL, but here it goes:
I presume that you have a closed-source application that wishes to use Qt under terms of LGPL.
Under some interpretations of U.S. law, making your code dependent on Qt's private headers makes it a derived work of Qt, so your code must be available under terms of LGPL (or GPL), unless you have a commercial license.
Your obligation under LGPL is to make it possible for people you distribute your app, to relink it with a version of Qt they compiled from the sources you're obliged to offer to them. This may be dynamic linking done by the OS, or static linking done with a linker utility. It doesn't matter whether you modified Qt or not. They ask, you must give them Qt sources with the exact build scripts you used to build the Qt that you use in your app.
When you depend on private headers, it's impossible for someone to make binary compatible changes to the Qt version you offer and relink it with your code, without things breaking. The private Qt classes can be changed without breaking binary compatibility - that's why they are private. Myself I interpret LGPL as follows: My code is not derived work if it will successfully link and work with any version of Qt that's binary-compatible to the version I offer along with my application. Of course that's within limits of Qt bugs and other changes I made, so it may not be viable for someone to patch this Qt to an older version and expect it to run OK.
So, the only thing you can do to keep your code closed-source is to modify the *public interface of QProcess within Qt proper. Anyone can take this modified version of Qt (that you offer!), make further binary compatible changes to it, and relink with your code. So if you think that not modifying Qt and depending on private headers makes your life easier, you are quite off base.
Generally speaking, you can't inherit from QXyzPrivate since you need to include Qt's private headers. So that's not a good practice, and there's really no good reason to do it. The price you pay is an extra heap allocation when you instantiate the class, so I'd say don't worry about it.
You must start your own private PIMPL class hierarchy. Note how each class that intends to be derived from must offer a constructor taking a reference to an instance of the private class.
// myprocess.h
class MyProcessPrivate;
class MyProcess : public QProcess {
Q_DECLARE_PRIVATE(MyProcess) // No semicolon!
public:
explicit MyProcess(int arg, QObject * parent = 0);
~MyProcess();
protected:
MyProcess(MyProcessPrivate&, int arg, QObject * parent); // Must be present to allow derivation
const QScopedPointer<MyProcessPrivate> d_ptr; // Only in the base class, must be protected!
}
// myprocess_p.h
class MyProcessPrivate {
Q_DECLARE_PUBLIC(MyProcess) // No semicolon!
...
public:
explicit MyProcessPrivate(MyProcess*);
protected:
MyProcess * const q_ptr; // Only in the base class, must be protected!
};
// derivedprocess.h
#include "myprocess.h"
class DerivedProcessPrivate;
class DerivedProcess {
Q_DECLARE_PRIVATE(DerivedProcess) // No semicolon!
public:
explicit DerivedProcess(int arg, QObject * parent = 0);
~DerivedProcess();
}
// derivedprocess_p.h
#include "myprocess_p.h"
class DerivedProcessPrivate : public MyProcessPrivate {
Q_DECLARE_PUBLIC(DerivedProcess) // No semicolon!
//...
public:
explicit DerivedProcessPrivate(DerivedProcess*);
};
// myprocess.cpp
MyProcess::MyProcess(int arg, QObject * parent) :
QProcess(parent),
d_ptr(new MyProcessPrivate(this)) {}
MyProcess::MyProcess(MyProcessPrivate & d, int arg) :
d_ptr(&d) {}
MyProcessPrivate::MyProcessPrivate(MyProcess* parent) :
q_ptr(parent) {}
// derivedprocess.cpp
DerivedProcess::DerivedProcess(int arg, QObject * parent) :
MyProcess(* new DerivedProcessPrivate(this), arg, parent) {}
DerivedProcessPrivate::DerivedProcessPrivate(DerivedProcess* parent) :
MyProcessPrivate(parent) {}
It can be accessed by d_ptr.data().
I want to extend the behaviors of QML without recompiling Qt source code, which need access to d_ptr. Here's how I get the QTextDocument in d_ptr of QDeclarativeTextEdit in an inherit class:
QT_FORWARD_DECLARE_CLASS(QDeclarativeTextEditPrivate)
class MyTextEdit : public QDeclarativeTextEdit
{
...
void aMethod()
{
QDeclarativeTextEditPrivate *d = reinterpret_cast<QDeclarativeTextEditPrivate *>(QDeclarativeItem::d_ptr.data());
QTextDocument *d_doc = d->document;
...
}
};
btw, we can also get d_ptr without inheriting classes.
For example, here's how I get QTextDocument in QDeclaractiveTextEditPrivate without inheritance:
#include <QtGui/QGraphicsItem>
QT_FORWARD_DECLARE_CLASS(QGraphicsItemPrivate)
class DQGraphicsItem : public QGraphicsItem
{
DQGraphicsItem() {}
public:
QGraphicsItemPrivate *d() const { return d_ptr.data(); }
};
inline QGraphicsItemPrivate *d_qgraphicsitem(const QGraphicsItem *q)
{ return static_cast<const DQGraphicsItem *>(q)->d(); }
#include <qt/src/declarative/graphicsitems/qdeclarativetextedit_p.h>
#include <qt/src/declarative/graphicsitems/qdeclarativetextedit_p_p.h>
inline QDeclarativeTextEditPrivate *d_qdeclarativetextedit(const QDeclarativeTextEdit *q)
{ return static_cast<QDeclarativeTextEditPrivate *>(d_qgraphicsitem(q)); }
inline QTextDocument *d_qdeclarativetextedit_document(const QDeclarativeTextEdit *q)
{ return d_qdeclarativetextedit(q)->document; }

porting C++ library to .NET

I have this simple library written in C++ (source code included)
struct MyStruct
{
char message[ 90 ];
int t;
};
enum MyEnum
{
MY_ENUM_1, MY_ENUM_2
};
class IEvent
{
public:
virtual ~IEvent() {}
virtual void event1( time_t ) = 0;
virtual void event2( MyStruct s ) = 0;
virtual void event3( MyEnum e ) = 0;
};
class Impl;
class MY_API Controller
{
public:
Controller( IEvent* eventListener );
~Controller();
void addListener( IEvent* eventListener );
void removeListener( IEvent* eventListener );
void f1( MyEnum e );
void f2();
private:
Impl* mImpl;
};
The code is implemented in C++11. I need to port this code to .NET.
I thought that a good choice can be C++/CLI but after lots of google I didn't find nothing.
Does someone know how to port this code in C++/CLI? I am able to build all the library in C++/CLI but the library doesn't export any symbols.
Edit1
The library is huge and a re-write in other language is too expensive.
If you want to port this code to .NET, to be used in other .NET languages, such as C#, then you're going to want to re-work how this library does things. Regardless of what language you choose to implement in, if your goal is to be consumed by other .NET languages, you should switch to the .NET paradigms.
For example: currently, you have an abstract class named IEvent. You could create a .NET interface named IEvent, and implement it the same way, but that's not how you do things in .NET. Instead, you'd want to define 3 delegate types, and have your Controller class define 3 events of those delegate types. Instead of addListener and removeListener, each of the events would have add and remove methods (accessed through += and -=).
delegate void Event1Handler(object sender, DateTime data);
delegate void Event2Handler(object sender, MyStruct data);
delegate void Event3Handler(object sender, MyEnum data);
public class EventExample_Controller
{
public event Event1Handler Event1;
public event Event2Handler Event2;
public event Event3Handler Event3;
}
As for the language to use, my initial response would be "C# if you can, C++/CLI if you have to". You haven't said what this library does, it may not be easy, or even possible, to do it in C#. But if you can do it in C#, then you'll get the benefits that language provides: Many of the benefits have equivalents in C++/CLI (e.g., linq query syntax can be represented with regular syntax, extension methods can be called as regular static methods, everything using the async keyword can be done with Tasks and a crapload of state variables), but some are C# only (e.g., having one assembly that works in 32-bit and 64-bit mode).
As for your try to compile the library as-is in C++/CLI, you need to mark the classes as managed classes. Change the classes to public ref class, and the enums to public enum class, and that'll create them as managed. Your next step will be to switch all your pointers to your own classes from unmanaged pointers (*) to managed references (^), and use gcnew instead of new for them.

Options for program

I am doing some algorithmic work using C++. My algorithms have some options which I need to be able to add to my program with as little effort as possible. I am currently using this code.
Everything works as expected: I added some code to my program so I can call the binary with arguments like -oopt1=val1,opt2=val2 and the options are set automatically.
The problem is that I am also writing a GUI at the same time. Now every kind of option has to be able to be set/requested using the GUI. However, I might need a spinbox for an integer value and a check box for a boolean option. I am using Qt as a toolkit, so I could just write a member
function that returns a QWidget* which is the appropriate base class.
However, I do not want any GUI-specific code in the header where I declare my options, since I would like to separate the GUI from the rest of the program. I could subclass any Option to create an appropriate QWidget*, but if I get a list of OptBase*, I wouldn't know what kind of widget I should create.
Is there some way that I can keep the GUI separated from the rest of the program while still being able to create appropriate widgets?
For me the solution is to create an abstract factory :
The factory should have an interface with two abstract methods to createBoolOption and CreateChoiceOption. Possibly more methods are needed
You can then make two concrete implementations of this interface where one is returning the same ones as you are doing now, but when you are running in QT you can use a different implementation that returns an optbase derived class that does know how to create a widget.
You can even use multiple inheritance (ie a second interface) so that you don't have to create a method in the first interface to specifically create a widget.
Of course then in running the QT application you have to explicitely cast to the second interface, when you want to create the widget.
The abstract factory itself should be passed to constructor of algobase. Ie dependency injection.
class ifactory{
public:
virtual Option<bool>* createBoolOption()=0;
virtual ChoiceOption<Mode>* createChoiceOption()=0;
virtual Widget* createWidget()=0; //here or in another interface
};
class ConcreteNonGuiFactory : public ifactory{
virtual Option<bool>* createBoolOption();
virtual ChoiceOption<Mode>* createChoiceOption();
virtual Widget* createWidget()={;};
};
class ConcreteGuiFactory : public ifactory{
virtual Option<bool>* createBoolOption();
virtual ChoiceOption<Mode>* createChoiceOption();
virtual Widget* createWidget();
};
class Algo1 : public AlgoBase{
public:
Algo1(ifactory& f):factory(f){
ChoiceOption<Mode>* opt = factory.createChoiceOption();
}
private:
ifactory factory;
}
If the creation of the widget is in a different interface you can reduce your dependencies.
In this example at least the widget has to be forward declared.
You need a bunch of variables to be accessed by both setter (GUI, commang-line parser) and getter (algorithm function). QVariant should be fine. As you options have names, they also have implicitly types. Getter should retrieve the value by their name and explicitly make type conversion. Setter shouldn't care - QVariant will.
Create a singleton instance which has a map of option-names. Implement slots triggered by GUI value-change signals, set values in map.
e.g:
class VarTable
{
static VarTable & instance(){ static VarTable inst; return inst; }
QMap<QString, QVariant> _map;
public:
void setVar( QString n, QVariant v ){ _map[n] = v };
QVariant getVar( QString n ) const { return _map[n]; }
};
//Call in Slot triggered by a value-change signal (e.g. QEditLine::returnPressed)
VarTable::instance().setVal( "option1", val1 );
//Regrieve in non-gui code
QString option1 = VarTable::instance().getVal( "option1" ).toString();
Regards
P.S.: I've not compiled the code, mey have some typos.