I'm trying to store enum in SQLite database using QSql.
I have following class:
partydao.h:
class PartyDao : public QObject
{
public:
enum partyType { typeCompany, typePerson };
private:
Q_OBJECT
Q_ENUMS(partyType)
Q_PROPERTY(partyType type READ type WRITE set_type)
// other declarations
};
Q_DECLARE_METATYPE(PartyDao::partyType)
partydao.cpp:
#include "partydao.h"
static int id = qRegisterMetaType<PartyDao::partyType>("partyType");
I do insert like this:
PartyDao p;
p.setProperty("type", QVariant::fromValue(PartyDao::typePerson));
QSqlQuery query;
query.prepare("INSERT INTO party (type) values (:type)");
qDebug() << p.property("type").isNull();
query.bindValue(":type", p.property("type"));
query.exec();
Although qDebug() prints "false" (i.e. property is not null), null value is stored in db.
I've tried with column of type TEXT and INTEGER with no success.
Can you tell me what I'm doing wrong?
EDIT:
I've just checked and QVariant holding my enum claims it can't be converted to QString or int (canConvert<int>() and canConvert<QString>() return false). Is there a way to add this conversion?
I didn't find any way to use auto conversion of QVariants of user type. Therefore I've created singleton storing rules for conversion.
struct DbConverter
{
virtual ~DbConverter() {}
virtual QVariant toDbValue(const QVariant &value) = 0;
virtual QVariant fromDbValue(const QVariant &value) = 0;
};
class DbConversion
{
public:
static QVariant toDbValue(const QVariant &value)
{
return instance()->m_converters.contains(value.userType()) ?
instance()->m_converters[value.userType()]->toDbValue(value) :
value;
}
static QVariant fromDbValue(int type, const QVariant &value)
{
return instance()->m_converters.contains(type) ?
instance()->m_converters[type]->fromDbValue(value):
value;
}
static int setConverter(int typeId, DbConverter *converter)
{
instance()->m_converters[typeId] = converter;
return typeId;
}
private:
static DbConversion *instance()
{
static DbConversion *inst = new DbConversion;
return inst;
}
QHash<int, DbConverter*> m_converters;
};
I register my custom types using value returned from qRegisterMetaType() and perform conversions on each app<->db transfer.
Please let me know if you find any more elegant solution and I'll be happy to accept your answer.
Just assign initial value to the first element in your enum, and the compiler will auto-increment any further definitions, then save this value to your database? You may have to cast it back and forth between an int, but qvariant should take care of that for you.
ie
enum partyType { typeCompany=1, typePerson };
Related
In order to convert an enum in C++ to a QString one can do the following:
template<typename QEnum>
static QString QtEnumToString (const QEnum value)
{
QString valueString = QVariant::fromValue(value).toString();
return valueString;
}
This will generate a QString for an enum declared as:
enum class Type{Text, Html, Image, URL};
Q_ENUM(Type)
Q_DECLARE_METATYPE(ClipboardItem::Type) // this goes outside the class
So for example the output of:
qDebug() << ClipboardItem::QtEnumToString(Type::Html);
is "Html".
Now I would like to do the reverse operation but couldn't find a way. What I have tried is this:
static QVariant::Type QStringToQtEnum (const char *name)
{
return QVariant::nameToType(name);
}
However, if I try to run QStringToQtEnum("Type::Html") the output is always QVariant::Invalid.
I'm trying to convert a QVariantMap to a custom class derived from QObject but I'm getting the return value of false from setProperty() when it comes to set the property of my enum type. Code goes below:
The MessageHeader.h file:
// deserialization class header
class MessageHeader : public QObject
{
Q_OBJECT
public:
MessageHeader(QObject *parent = 0);
~MessageHeader();
enum class MessageType
{
none = 0,
foo = 1,
baa = 2
};
Q_ENUM(MessageType)
Q_PROPERTY(MessageType type READ getType WRITE setType)
Q_PROPERTY(int ContentLength READ getContentLength WRITE setContentLength)
void setType(MessageType type);
void setContentLength(int ContentLength);
MessageType getType();
int getContentLength();
QString toString();
MessageType type = MessageType::none;
int ContentLength = 0;
};
The MessageHeader.cpp file:
MessageHeader::MessageHeader(QObject *parent)
: QObject(parent)
{
}
MessageHeader::~MessageHeader()
{
}
MessageType MessageHeader::getType()
{
return type;
}
int MessageHeader::getContentLength()
{
return ContentLength;
}
void MessageHeader::setType(MessageType type)
{
this->type = type;
}
void MessageHeader::setContentLength(int ContentLength)
{
this->ContentLength = ContentLength;
}
QString MessageHeader::toString()
{
return QString("NOT IMPLEMENTED YET");
}
And the deserialize function template helper:
template<typename T>
T* Deserialize(const QString &json)
{
bool status = false;
QJson::Parser parser;
QVariantMap map = parser.parse(json.toUtf8(), &status).toMap();
if(!status)
return NULL;
T *obj = new T(); //don't worry about this, I'll rather take this from paramters once this is working
QObject *p = (QObject *) obj; // cast done so that I see setProperty() method
for(QVariantMap::const_iterator iter = map.begin(); iter != map.end(); ++iter)
{
const char *name = iter.key().toLatin1();
const QVariant value = iter.value();
qDebug() << "setting " << name << "=" << value;
// the issue goes below. Here setProperty() return false.
// At this point, name = 'type' and value = 2
assert(p->setProperty(name, value));
}
//QJson::QObjectHelper::qvariant2qobject(map, obj);
return obj;
}
The JSON input string to above function is like this:
"{\"ContentLength\": 100, \"type\": 2}"
The enum type is registered in the main funcction before anything else:
qRegisterMetaType<MessageType>("MessageType");
And here's the QJson library used in this example. I build it on Windows with this .pro file
EDIT:
I just found that the type property can't be find by indexOfProperty()
qDebug() << "id = " << meta->indexOfProperty(name); // print -1, name = 'type'
The enum property can only be set if the variant type is either a QString, QInt or QUInt as could be seen here. So to successfully set the enum property, the variant needs to be one of these types and nothing else. QJson parses any unsigned integers as QULongLong as can be seen here, line 84. So one way is to fork QJson and modify the code so the integer values are converted to QInt and QUInt or read/write the enum values as strings.
Also, putting statements within an assert is not a good idea, but I assume you just wrote that code trying to figure out the problem.
Just as a side note, according to Qt documentation,
[qRegisterMetaType] is useful only for registering an alias (typedef) for every other use case Q_DECLARE_METATYPE and qMetaTypeId() should be used instead.
so replacing qRegisterMetaType<MessageHeader::MessageType>("MessageType") with Q_DECLARE_METATYPE(MessageHeader::MessageType) in your header would be a reasonable move.
Building up on Rostislav's answer, if you have no choice but to receive a QULongLong as input, here is a code snippet to convert it if the property to set is an enum:
#include <QMetaProperty>
const QMetaObject* meta = object->metaObject();
const int index = meta->indexOfProperty(propName);
if (index == -1) {/* report error*/}
if (meta->property(index).isEnumType())
// special case for enums properties: they can be set from QInt or QUInt variants,
// but unsigned integers parsed from json are QULongLong
object->setProperty(propName, propVariant.value<unsigned int>());
else
object->setProperty(propName, propVariant);
I have some class like this:
class QObjectDerived : public QObject
{
Q_OBJECT
// ...
};
Q_DECLARE_METATYPE(QObjectDerived*)
When this class was stored to QVariant such behaviour occures
QObjectDerived *object = new QObjectDerived(this);
QVariant variant = QVariant::fromValue(object);
qDebug() << variant; // prints QVariant(QObjectDerived*, )
qDebug() << variant.value<QObject*>(); // prints QObject(0x0)
qDebug() << variant.value<QObjectDerived*>(); // QObjectDerived(0x8c491c8)
variant = QVariant::fromValue(static_cast<QObject*>(object));
qDebug() << variant; // prints QVariant(QObject*, QObjectDerived(0x8c491c8) )
qDebug() << variant.value<QObject*>(); // prints QObjectDerived(0x8c491c8)
qDebug() << variant.value<QObjectDerived*>(); // QObject(0x0)
Is there any way to store it in QVariant and be able to get it as QObject* and QObjectDerived*?
Only by writing
QObject *value = variant.value<QObjectDerived*>();
It may be possible to partially specialize qvariant_cast for your type, but that's not a documented supported use case, and I'd be reluctant to rely on it.
qvariant.h (Qt 4.8.6):
template<typename T>
inline T value() const
{ return qvariant_cast<T>(*this); }
...
template<typename T> inline T qvariant_cast(const QVariant &v)
{
const int vid = qMetaTypeId<T>(static_cast<T *>(0));
if (vid == v.userType())
return *reinterpret_cast<const T *>(v.constData());
if (vid < int(QMetaType::User)) {
T t;
if (qvariant_cast_helper(v, QVariant::Type(vid), &t))
return t;
}
return T();
}
QObject * is stored as a built-in QMetaType::QObjectStar type, and QObjectDerived is a user-defined type with id, defined by Meta-type system. Which means, you'll have to cast it manually.
How would I return a(n existing) pointer to a known type from a string of its name? Say I created some map<string, double> called map1 and some vector<string> called vec1. I'd like to write a function that will return map1 from "map1" and vec1 from "vec1" (and an additional argument specifying the respective type of each).
Is this possible?
My ultimate goal is to get a QWidget by its name in QString form, since I'm working with a large number of them, though an answer should be framework-independent, right?
You need to perform some kind of dynamic dispatch. To do so you can simply start with exactly what you proposed:
enum class types { A = 0, B = 1 };
void (*handlers[])(void*) = { &HandleA, &HandleB };
::std::unordered_map<::std::string, ::std::tuple<types, void*>> registry;
Now all that remains is to perform the lookup:
void lookup(::std::string const& name)
{
auto& t = registry.at(name);
handlers[static_cast<size_t>(::std::get<0>(t))](::std::get<1>(t));
}
Automagic argument casting for handlers
The handlers all take an argument of type void* - this can be dealt with by adding a little template magic:
template<typename T, void(*f)(T*)>
void handle(void* arg)
{
f(static_cast<T*>(arg));
}
void (*handlers[])(void*) = { &handle<A, &HandleA>, &handle<B, &HandleB> };
Now, the prototype is e.g. void HandleA(A*).
Simple adding of objects to registry
With the current code, you can add objects to your registry like so:
A a;
registry.emplace("A #1", ::std::make_tuple(types::A, &a));
While this works perfectly, we would like to do something a bit more elegant. Let us start by changing the enum class types to something which also knows about the type we whish to represent it:
template<typename T> struct types;
template<> struct types<A> { static const size_t id = 0; };
template<> struct types<B> { static const size_t id = 1; };
Of course, now we need to fix the registry type:
::std::unordered_map<::std::string, ::std::tuple<size_t, void*>> registry;
And finally we can provide a simple insert function:
template<typename T>
void insert(::std::string const& name, T* object)
{
registry.emplace(name, ::std::make_tuple(types<T>::id, static_cast<void*>(object)));
}
Final usage example
A a;
insert("A #1", &a);
lookup("A #1");
The meta-object system already handles this, so the answer will be framework-specific because you generally need a code generator to get metadata about the C++ types that's not otherwise available.
QLineEdit * ed = ...;
ed->setObjectName("myObject");
... elsewhere in the code
foreach(QWidget * w, QCoreApplication::allWidgets()) {
// Lookup by name
if (w->objectName() == "myObject") {
...
}
// Lookup by type
if (qobject_cast<QLineEdit*>(w)) {
...
}
}
If you want to speed up the lookup, and the objects have unique names:
class Widgets {
typedef QMap<QString, QPointer<QWidget>> Data;
mutable Data m_map;
public:
Widgets() {
foreach(QWidget * w, QCoreApplication::allWidgets()) {
if (w->objectName().isEmpty()) continue;
m_map.insert(w->objectName(), w);
}
}
QWidget * lookupWidget(const QString & name) const {
Data::iterator it = m_map.find(name);
if (it == m_map.end()) return nullptr;
QWidget * w = it->data();
if (!w) m_map.erase(it); // The widget doesn't exist anymore
return w;
}
template <typename T> T * lookup(const QString & name) const {
return qobject_cast<T*>(lookupWidget(name));
}
void setName(QWidget * w, const QString & name) {
Q_ASSERT(! name.isEmpty());
w->setObjectName(name);
m_map.insert(name, w);
}
};
In your code, use widgets->setName() instead of setObjectName.
If you want to look-up by both name and type, where duplicate names are OK as long as they are all of different types:
class Widgets2 {
typedef QPair<QString, QString> Key;
typedef QMap<Key, QPointer<QWidget>> Data;
mutable Data m_map;
static Key keyFor(QWidget * w) {
return qMakePair(w->objectName(),
QString::fromLatin1(w->metaObject()->className()));
public:
Widgets2() {
foreach(QWidget * w, QCoreApplication::allWidgets()) {
if (w->objectName().isEmpty()) continue;
m_map.insert(keyFor(w), w);
}
}
QWidget * lookupWidget(const QString & name, const QString & type) const {
Data::iterator it = m_map.find(qMakePair(name, type));
if (it == m_map.end()) return nullptr;
QWidget * w = it->data();
if (!w) m_map.erase(it); // The widget doesn't exist anymore
return w;
}
template <typename T> T * lookup(const QString & name) const
{
return qobject_cast<T*>(lookupWidget(name,
QString::fromLatin1(T::staticMetaObject.className())));
}
void setName(QWidget * w, const QString & name) {
Q_ASSERT(! name.isEmpty());
w->setObjectName(name);
m_map.insert(keyFor(w), w);
}
};
The lookup works as follows:
widgets2->lookup<QLineEdit>("myObject")->setText("foo");
I'm leveraging the QObject and QPointer to make the widget registry safe to widget deletions - you won't ever get a dangling pointer back.
It is also possible to track object name changes, if you so wish: QObject emits the objectNameChanged signal.
All of this is of course a horrible hack around a broken design of your code. The fact that you need this means that you're very tightly coupling business logic and the GUI. You should use some kind of model-view architecture.
How to Define or Implement C# Property in ISO C++ ?
Assume following C# code :
int _id;
int ID
{
get { return _id; }
set { _id = value; }
}
I know C# convert the get and set lines to getXXX and setXXX methods in compile time. in C++ , programmers usually define these two function manually like :
int _id;
int getID() { return _id; }
void setID(int newID) { _id = newID; }
but, I want to have the C# syntax or a stuff like it in order to have a simple usability.
In C#, we can use properties like :
ID = 10; // calling set function
int CurrentID = ID; // calling get function
In C++, we can use our function like :
setID(10); // calling set function
int CurrentID = getID(); // calling get function
Now tell me how can I implement the C# properties in ISO C++.
thanks.
As Alexandre C. has already stated, it's very awkward and not really worth it, but to give an example of how you might do it.
template <typename TClass, typename TProperty>
class Property
{
private:
void (TClass::*m_fp_set)(TProperty value);
TProperty (TClass::*m_fp_get)();
TClass * m_class;
inline TProperty Get(void)
{
return (m_class->*m_fp_get)();
}
inline void Set(TProperty value)
{
(m_class->*m_fp_set)(value);
}
public:
Property()
{
m_class = NULL;
m_fp_set = NULL;
m_fp_set = NULL;
}
void Init(TClass* p_class, TProperty (TClass::*p_fp_get)(void), void (TClass::*p_fp_set)(TProperty))
{
m_class = p_class;
m_fp_set = p_fp_set;
m_fp_get = p_fp_get;
}
inline operator TProperty(void)
{
return this->Get();
}
inline TProperty operator=(TProperty value)
{
this->Set(value);
}
};
In your class where you wish to use it, you create a new field for the property, and you must call Init to pass your get/set methods to the property. (pref in .ctor).
class MyClass {
private:
int _id;
int getID() { return _id; }
void setID(int newID) { _id = newID; }
public:
Property<MyClass, int> Id;
MyClass() {
Id.Init(this, &MyClass::getID, &MyClass::setID);
}
};
Short answer: you can't.
Long answer: You could try to simulate them via proxy classes, but believe me this is not worth the minor incovenience in having set/get functions.
You'd have basically to define a class which forwards all the behavior of the variable. This is insanely hard to get right, and impossible to be made generic.
Quite simply. I'd argue this even has no overhead compared to making the variable public. However, you can't modify this any further. Unless, of course, you add two more template parameters that are call backs to functions to call when getting and setting.
template<typename TNDataType>
class CProperty
{
public:
typedef TNDataType TDDataType;
private:
TDDataType m_Value;
public:
inline TDDataType& operator=(const TDDataType& Value)
{
m_Value = Value;
return *this;
}
inline operator TDDataType&()
{
return m_Value;
}
};
EDIT: Don't make the call back functions template parameters, just data members that are constant and must be initialized in the constructor for the property. This inherently has greater overhead than simply writing a get and set method your self, because you're making function calls inside of your gets and sets this way. The callbacks will be set at run-time, not compile-time.