Solved crash in QListWidget::dropEvent when I add a UserRole to my QListItemWidget :'(
-
@mpergand
yeah, its pretty odd why one cant step into the function then.
( since it wants it )I assume at run time, it maps to others overloads then.
update:
in any case, steaming it out/in and using it seems to work :) -
I'm unable to retreive the variant.
QDataStream out(&encoded, QIODevice::ReadOnly); QVariant v2; out>>v2; QDataStream &operator>>(QDataStream &in, FooClass*& foo) { in>>foo; -> It crashes here
-
@VRonin said in crash in QListWidget::dropEvent when I add a UserRole to my QListItemWidget :'(:
http://lengthily.blogspot.com/2017/02/one-size-fits-all.html
Also keep in mind that Qt-parent child relationship does not know about your design so it might delete stuff you didn't intend toWell, I said manager to not enter in the details... but basically it's a subclass of QApplication that owns my Model (which own all the Elements). It also owns the HMI if there is one.
class MyApplication : public QApplication { private: const AppMode _mode; AppLang _lang; Model *_model; MainWindow *_hmi; static const QMap<AppLang, QString> sAppLanguages; static const QString sTranslationsFileName; static const QString sVersion; static const QString sAppName; ... };
However I use singleton for some thread safe objects as a convenient way to be able to get the instance from anywhere in the code. Mainly for to get my LogService, the IconFactory, the UndoStack and the IOService.
I think it has some sense and it is practical to be able to do such calls:Iconfactory::getInstance()->getElementTypeIcon(elem->getElementType); UndoStack::getInstance()->beginMacro(macroLabel);
Here is what the Singleton class I use:
#ifndef SINGLETON_H #define SINGLETON_H template <typename T> class Singleton { protected: // Constructor /Destructor Singleton() = default; virtual ~Singleton() = default; public: Singleton(const Singleton &other) = delete; Singleton(const Singleton &&other) = delete; Singleton & operator=(const Singleton &other) = delete; Singleton & operator=(const Singleton &&other) = delete; // Public Interface static T *getInstance(){ if (!_singleton) { _singleton = new T; } return (static_cast<T*> (_singleton)); } static void kill() { if (_singleton) { delete _singleton; _singleton = nullptr; } } private: // Unique instance static T *_singleton; }; template <typename T> T *Singleton<T>::_singleton; #endif // SINGLETON_H
Rq: for Services, I generally derive from this PureStaticClass
class PureStaticClass { PureStaticClass() = delete; PureStaticClass(const PureStaticClass &other) = delete; PureStaticClass(const PureStaticClass &&other) = delete; PureStaticClass & operator=(const PureStaticClass &other) = delete; PureStaticClass & operator=(const PureStaticClass &&other) = delete; };
@VRonin said in crash in QListWidget::dropEvent when I add a UserRole to my QListItemWidget :'(:
Also keep in mind that Qt-parent child relationship does not know about your design so it might delete stuff you didn't intend to
Yes I'm aware of that, I do it only for my Data Object that aren't updated directly by any QT objects. Those objects will have a pointer on them to extract some data but never delete it.
-
@mpergand
I've tried that and it doesn't work with work on my env. I'm still getting the issue:QVariant::save: unable to save type 'Element*' (type id: 1025).
Here is my code:
#include <QDataStream> class Element; inline QDataStream &operator>>(QDataStream &in, Element*& elem) { in >> elem; return in; } inline QDataStream &operator<<(QDataStream &in, Element*& elem) { in << elem; return in; }
if I override the startDrag event like this:
void ItemOfferingListWidget::startDrag(Qt::DropActions supportedActions) { // return QListWidget::startDrag(supportedActions); Q_UNUSED(supportedActions) QMimeData *mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); for (QListWidgetItem *item : selectedItems()) { QMap<int, QVariant> data; data[Qt::UserRole] = item->data(Qt::UserRole); // Element *elem = item->data(Qt::UserRole).value<Element*>(); // qulonglong ptrval(*reinterpret_cast<qulonglong *>(&elem)); stream << row(item) << data; // stream << row(item) << elem->getId() << elem->getElementTypeName(); } mimeData->setData("application/x-qabstractitemmodeldatalist", encodedData); QDrag *drag = new QDrag(this); drag->setMimeData(mimeData); drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction); }
The error message kicks in when I try to write the data in the stream.
I'm jumping intemplate <class Key, class T> inline QDataStream &operator<<(QDataStream &s, const QMap<Key, T> &map) { return QtPrivate::writeAssociativeContainer(s, map); }
but never in my overriden function :(
-
My fault, I totally forgot you also need qRegisterMetaTypeStreamOperators
P.S.
I still don't like your design but at the end of the day if you are happy with it and it works, go for it -
@VRonin said in crash in QListWidget::dropEvent when I add a UserRole to my QListItemWidget :'(:
My fault, I totally forgot you also need qRegisterMetaTypeStreamOperators
Ok, now I don't have the "QVariant::save: unable to save type 'Element*' (type id: 1025).
" message but the app is crashing in an infinite loop in:inline QDataStream &operator>>(QDataStream &in, Element*& elem) { in >> elem; return in; }
on the first line...
Thread 1 (Thread 0x7ffff7fb8140 (LWP 16621)): #0 0x000055555557fd65 in operator>> (in=..., elem=@0x7fffffffa280: 0x0) at ../src_cosi7/Model/Element.h:370 No locals. #1 0x000055555557fd6a in operator>> (in=..., elem=@0x7fffffffa280: 0x0) at ../src_cosi7/Model/Element.h:370 No locals. #2 0x000055555557fd6a in operator>> (in=..., elem=@0x7fffffffa280: 0x0) at ../src_cosi7/Model/Element.h:370 No locals. #3 0x000055555557fd6a in operator>> (in=..., elem=@0x7fffffffa280: 0x0) at ../src_cosi7/Model/Element.h:370 No locals. #4 0x000055555557fd6a in operator>> (in=..., elem=@0x7fffffffa280: 0x0) at ../src_cosi7/Model/Element.h:370 No locals. #5 0x000055555557fd6a in operator>> (in=..., elem=@0x7fffffffa280: 0x0) at ../src_cosi7/Model/Element.h:370 No locals. #6 0x000055555557fd6a in operator>> (in=..., elem=@0x7fffffffa280: 0x0) at ../src_cosi7/Model/Element.h:370 No locals. #7 0x000055555557fd6a in operator>> (in=..., elem=@0x7fffffffa280: 0x0) at ../src_cosi7/Model/Element.h:370 No locals. #8 0x000055555557fd6a in operator>> (in=..., elem=@0x7fffffffa280: 0x0) at ../src_cosi7/Model/Element.h:370 ... #261515 0x000055555557fd6a in operator>> (in=..., elem=@0x7fffffffa280: 0x0) at ../src_cosi7/Model/Element.h:370 No locals. #261516 0x000055555557fd6a in operator>> (in=..., elem=@0x7fffffffa280: 0x0) at ../src_cosi7/Model/Element.h:370 No locals. #261517 0x0000555555580182 in QtMetaTypePrivate::QMetaTypeFunctionHelper<Element*, true>::Load (stream=..., t=0x7fffffffa280) at /opt/Qt/5.10.1/gcc_64/include/QtCore/qmetatype.h:777 No locals. #261518 0x00007ffff66c596a in QMetaType::load(QDataStream&, int, void*) () from /opt/Qt/5.10.1/gcc_64/lib/libQt5Core.so.5 No symbol table info available. #261519 0x00007ffff66ed12c in QVariant::load(QDataStream&) () from /opt/Qt/5.10.1/gcc_64/lib/libQt5Core.so.5 No symbol table info available. #261520 0x00007ffff66ed25f in operator>>(QDataStream&, QVariant&) () from /opt/Qt/5.10.1/gcc_64/lib/libQt5Core.so.5 No symbol table info available. #261521 0x00005555555ef34e in QtPrivate::readAssociativeContainer<QMap<int, QVariant> > (s=..., c=...) at /opt/Qt/5.10.1/gcc_64/include/QtCore/qdatastream.h:285 k = 256 t = {d = {data = {c = 0 '\000', uc = 0 '\000', s = 0, sc = 0 '\000', us = 0, i = 0, u = 0, l = 0, ul = 0, b = false, d = 0, f = 0, real = 0, ll = 0, ull = 0, o = 0x0, ptr = 0x0, shared = 0x0}, type = 1025, is_shared = 0, is_null = 0}} i = 0 stateSaver = {stream = 0x7fffffffa310, oldStatus = QDataStream::Ok} n = 3 #261522 0x00005555555eebff in operator>><int, QVariant> (s=..., map=...) at /opt/Qt/5.10.1/gcc_64/include/QtCore/qdatastream.h:436 No locals. #261523 0x00005555555ed678 in ItemOfferingListWidget::dropEvent (this=0x5555562138d0, event=0x7fffffffa8f0) at ../src_cosi7/hmi/GUI/widget/ItemOfferingListWidget.cpp:103 userRoleIter = {i = 0x7fffffffa480} mimeData = {d = 0x5555563d7f70} modelData = {d = 0x7ffff67e4940 <QMapDataBase::shared_null>} mimeReader = {d = {d = 0x5555563a35c0}, dev = 0x55555617f260, owndev = true, noswap = false, byteorder = QDataStream::BigEndian, ver = 17, q_status = QDataStream::Ok} row = 0 col = 0 __PRETTY_FUNCTION__ = "virtual void ItemOfferingListWidget::dropEvent(QDropEvent*)" #261524 0x00007ffff7735018 in QWidget::event(QEvent*) () from /opt/Qt/5.10.1/gcc_64/lib/libQt5Widgets.so.5 No symbol table info available.
-
That's because your code is an obvious infinite recursion. You have to fix it
-
Yes, there're something wrong with the >> operator.
Anyway, I think it's a oversized process just to save a single pointer ...
QDataStream allows to save/load a pointer to char:
operator<<(const char *s) operator>>(char *&s)
So, you simply need to use reinterpret_cast, back and forth for your custom class.
Et voilĂ -
Well I nearly lost a day on this so I think I'm just going to stay with my working version where I create my own QDrag and put by hand the reinterpret_cast of the address of my pointer.
It works well and I don't need the register and registerforstream of my metatype (neither to reimplement the stream operator on DataStream) -
@mpergand said in crash in QListWidget::dropEvent when I add a UserRole to my QListItemWidget :'(:
Yes, there're something wrong with the >> operator.
Anyway, I think it's a oversized process just to save a single pointer ...
QDataStream allows to save/load a pointer to char:
operator<<(const char *s) operator>>(char *&s)
So, you simply need to use reinterpret_cast, back and forth for your custom class.
Et voilĂYep that is what I'm doing but through a qulonglong instead of the char*
That's because your code is an obvious infinite recursion. You have to fix it
I pasted your code from the other post thinking the break would end the for loop. (I don't know the transaction objects you're using)
I've updated to be:const QByteArray mimeData = event->mimeData()->data("application/x-qabstractitemmodeldatalist"); QDataStream mimeReader(mimeData); int row, col; QMap<int,QVariant> modelData; while (!mimeReader.atEnd()) { mimeReader >> row >> col >> modelData; qDebug() << "Receiving row: " << row << " modelData.size: " << modelData.size(); const auto userRoleIter = modelData.constFind(Qt::UserRole); if(userRoleIter != modelData.cend()) { Element *elem = userRoleIter->value<Element*>(); qDebug() << "Receiving elem: " << elem->getName() << " (row in original list: " << row << ")"; } else{ qDebug() << "No UserRole..."; } }
but I still have the same issue...
I don't see the obvious recursive loop :(
this code is working well if I don't use the Qmap<int, QVariant> but build the QDrag myself.
Could you let me know what's wrong plz -
@mbruel said in crash in QListWidget::dropEvent when I add a UserRole to my QListItemWidget :'(:
I don't see the obvious recursive loop
inside
inline QDataStream &operator>>(QDataStream &in, Element*& elem) { in >> elem; return in; }
in >> elem;
callsQDataStream &operator>>(QDataStream &in, Element*& elem)
. that's the infinite recursion.Serialising pointers to objects as numerics tickles my evil detector, in any case, Qt has
qintptr
type that is designed for this -
@VRonin
ah yeah indeed... I've just copied the code without thinking cause without it and only the add of the qRegisterMetaTypeStreamOperators it wasn't working so I guess I need to reimplement the stream operator on DataStream .anyway, if I've to do that, and cast the pointer address, I don't see the point of doing all this. I'm just gonna cast directly in the dragStart in my own QDrag and decode it like I was doing in my working solution above.
Thanks for the qintptr, I'm going to use this instead of the qulonglong.