Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Stream operators for subclassed QTreeWidgetItem not invoked
Forum Updated to NodeBB v4.3 + New Features

Stream operators for subclassed QTreeWidgetItem not invoked

Scheduled Pinned Locked Moved Unsolved General and Desktop
10 Posts 3 Posters 598 Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • T Offline
    T Offline
    Taytoo
    wrote on last edited by Taytoo
    #1

    I've subclassed QTreeWidgetItem as XItem, it works fine in QTreeWidget except that when I attempt to do drag/drop operation, inside default StartDrag implementation it crashes trying to serialize an internal struct that's set as DataRole.

    To fix that I wrote stream operators for XItem that don't write DataRole. For somereason the stream operators are not being invoked and internally the default implementation for QTreeWidgetItem is being used, and I'm still getting the same exception.

    62685617-3f01-4382-8a52-a68dfa385e22-image.png

    kshegunovK VRoninV 2 Replies Last reply
    0
    • T Taytoo

      I've subclassed QTreeWidgetItem as XItem, it works fine in QTreeWidget except that when I attempt to do drag/drop operation, inside default StartDrag implementation it crashes trying to serialize an internal struct that's set as DataRole.

      To fix that I wrote stream operators for XItem that don't write DataRole. For somereason the stream operators are not being invoked and internally the default implementation for QTreeWidgetItem is being used, and I'm still getting the same exception.

      62685617-3f01-4382-8a52-a68dfa385e22-image.png

      kshegunovK Offline
      kshegunovK Offline
      kshegunov
      Moderators
      wrote on last edited by
      #2

      Please provide at least minimal code of how you do things. Also please post the stack trace as text and don't cut the leading part of it, I can't know what module what code resides in, nor should I.

      Read and abide by the Qt Code of Conduct

      T 1 Reply Last reply
      0
      • kshegunovK kshegunov

        Please provide at least minimal code of how you do things. Also please post the stack trace as text and don't cut the leading part of it, I can't know what module what code resides in, nor should I.

        T Offline
        T Offline
        Taytoo
        wrote on last edited by
        #3

        @kshegunov The module name is exe filename (which I wanted to hide).

        Here's the subclassed item (I took out some private methods, since they're not related to this functionality)

        class XItem : public QTreeWidgetItem {
        public:
        	friend QDataStream& operator<<(QDataStream& stream, const XItem & item);
        	friend QDataStream& operator>>(QDataStream& stream, XItem & item);
        
        	XItem () { };
        
        	XItem (QTreeWidget* parent) :QTreeWidgetItem(parent) {}
        
        };
        
        Q_DECLARE_METATYPE(XItem );
        

        Overloaded Stream operators

        QDataStream& operator<<(QDataStream& stream, const XItem& item)
        {
        	stream << item.text(0);
        	return stream;
        }
        
        QDataStream& operator>>(QDataStream& stream, XItem& item)
        {
        	QString text;
        	stream >> text;
        	item.setText(0, text);
        
        	return stream;
        }
        

        This is the struct that is set as the DataRole

        struct ListEntry
        {
        	int mapID = 0;
        
        	QString name;
        	QDateTime dtModified;
        };
        

        Here's how I'm setting the struct as DataRole

        item->setData(iData, Qt::UserRole, QVariant::fromValue<ListEntry*>(&entry));
        
        VRoninV kshegunovK 2 Replies Last reply
        0
        • T Taytoo

          I've subclassed QTreeWidgetItem as XItem, it works fine in QTreeWidget except that when I attempt to do drag/drop operation, inside default StartDrag implementation it crashes trying to serialize an internal struct that's set as DataRole.

          To fix that I wrote stream operators for XItem that don't write DataRole. For somereason the stream operators are not being invoked and internally the default implementation for QTreeWidgetItem is being used, and I'm still getting the same exception.

          62685617-3f01-4382-8a52-a68dfa385e22-image.png

          VRoninV Offline
          VRoninV Offline
          VRonin
          wrote on last edited by
          #4

          @Taytoo said in Stream operators for subclassed QTreeWidgetItem not invoked:

          inside default StartDrag implementation it crashes

          It doesn't look like it's crashing but rather asserting. What is the message that gets printed befor the crash?

          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
          ~Napoleon Bonaparte

          On a crusade to banish setIndexWidget() from the holy land of Qt

          T 1 Reply Last reply
          0
          • VRoninV VRonin

            @Taytoo said in Stream operators for subclassed QTreeWidgetItem not invoked:

            inside default StartDrag implementation it crashes

            It doesn't look like it's crashing but rather asserting. What is the message that gets printed befor the crash?

            T Offline
            T Offline
            Taytoo
            wrote on last edited by
            #5

            @VRonin Yes its a assert, but it actually stops program executing since its an error of sorts

            Message printed before assert:

            QVariant::save: unable to save type 'ListEntry*' (type id: 1031).
            
            ASSERT failure in QVariant::save: "Invalid type to save", file kernel\qvariant.cpp, line 2594
            Debug Error!
            
            Program: C:\Qt\5.12.5\msvc2017\bin\Qt5Cored.dll
            Module: 5.12.5
            File: kernel\qvariant.cpp
            Line: 2594
            
            ASSERT failure in QVariant::save: "Invalid type to save", file kernel\qvariant.cpp, line 2594
            
            (Press Retry to debug the application)
            QtTestProject.exe has triggered a breakpoint.
            

            Created a bare minimum program to figure out the issue. Here's the stack trace:

             	Qt5Cored.dll!qt_message_fatal(QtMsgType __formal, const QMessageLogContext & context, const QString & message) Line 1878	C++
             	Qt5Cored.dll!QMessageLogger::fatal(const char * msg, ...) Line 888	C++
             	Qt5Cored.dll!qt_assert_x(const char * where, const char * what, const char * file, int line) Line 3220	C++
             	Qt5Cored.dll!QVariant::save(QDataStream & s) Line 2594	C++
             	Qt5Cored.dll!operator<<(QDataStream & s, const QVariant & p) Line 2619	C++
            >	Qt5Cored.dll!QtPrivate::writeAssociativeContainer<QMap<int,QVariant> >(QDataStream & s, const QMap<int,QVariant> & c) Line 319	C++
             	Qt5Cored.dll!operator<<<int,QVariant>(QDataStream & s, const QMap<int,QVariant> & map) Line 444	C++
             	Qt5Cored.dll!QAbstractItemModel::encodeData(const QList<QModelIndex> & indexes, QDataStream & stream) Line 2598	C++
             	Qt5Cored.dll!QAbstractItemModel::mimeData(const QList<QModelIndex> & indexes) Line 1963	C++
             	Qt5Widgetsd.dll!QTreeModel::internalMimeData() Line 726	C++
             	Qt5Widgetsd.dll!QTreeWidget::mimeData(const QList<QTreeWidgetItem *> items) Line 3357	C++
             	Qt5Widgetsd.dll!QTreeModel::mimeData(const QList<QModelIndex> & indexes) Line 739	C++
             	Qt5Widgetsd.dll!QAbstractItemView::startDrag(QFlags<enum Qt::DropAction> supportedActions) Line 3681	C++
             	Qt5Widgetsd.dll!QAbstractItemView::mouseMoveEvent(QMouseEvent * event) Line 1839	C++
             	Qt5Widgetsd.dll!QTreeView::mouseMoveEvent(QMouseEvent * event) Line 1983	C++
             	Qt5Widgetsd.dll!QWidget::event(QEvent * event) Line 8940	C++
             	Qt5Widgetsd.dll!QFrame::event(QEvent * e) Line 550	C++
             	Qt5Widgetsd.dll!QAbstractScrollArea::viewportEvent(QEvent * e) Line 1221	C++
             	Qt5Widgetsd.dll!QAbstractItemView::viewportEvent(QEvent * event) Line 1751	C++
            
            
            1 Reply Last reply
            0
            • T Taytoo

              @kshegunov The module name is exe filename (which I wanted to hide).

              Here's the subclassed item (I took out some private methods, since they're not related to this functionality)

              class XItem : public QTreeWidgetItem {
              public:
              	friend QDataStream& operator<<(QDataStream& stream, const XItem & item);
              	friend QDataStream& operator>>(QDataStream& stream, XItem & item);
              
              	XItem () { };
              
              	XItem (QTreeWidget* parent) :QTreeWidgetItem(parent) {}
              
              };
              
              Q_DECLARE_METATYPE(XItem );
              

              Overloaded Stream operators

              QDataStream& operator<<(QDataStream& stream, const XItem& item)
              {
              	stream << item.text(0);
              	return stream;
              }
              
              QDataStream& operator>>(QDataStream& stream, XItem& item)
              {
              	QString text;
              	stream >> text;
              	item.setText(0, text);
              
              	return stream;
              }
              

              This is the struct that is set as the DataRole

              struct ListEntry
              {
              	int mapID = 0;
              
              	QString name;
              	QDateTime dtModified;
              };
              

              Here's how I'm setting the struct as DataRole

              item->setData(iData, Qt::UserRole, QVariant::fromValue<ListEntry*>(&entry));
              
              VRoninV Offline
              VRoninV Offline
              VRonin
              wrote on last edited by
              #6

              Looks pretty clear as an error, you don't need the stream operators for XItem but for ListEntry*

              P.S.
              Stream operators for pointers usually are a bad idea but depends on how your internal data is structured

              "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
              ~Napoleon Bonaparte

              On a crusade to banish setIndexWidget() from the holy land of Qt

              T 1 Reply Last reply
              2
              • VRoninV VRonin

                Looks pretty clear as an error, you don't need the stream operators for XItem but for ListEntry*

                P.S.
                Stream operators for pointers usually are a bad idea but depends on how your internal data is structured

                T Offline
                T Offline
                Taytoo
                wrote on last edited by
                #7

                @VRonin Yes, I also tried creating stream operators for ListEntry but still got the assert. Do I need separate Stream operators for ListEntry and ListEntry* ?

                For now, I'm just saving ListEntry* pointer as qlonglong in QVariant, that takes care of QVariant throwing up while serializing/deserializing. Still would like to know what the proper solution is.

                VRoninV 1 Reply Last reply
                0
                • T Taytoo

                  @VRonin Yes, I also tried creating stream operators for ListEntry but still got the assert. Do I need separate Stream operators for ListEntry and ListEntry* ?

                  For now, I'm just saving ListEntry* pointer as qlonglong in QVariant, that takes care of QVariant throwing up while serializing/deserializing. Still would like to know what the proper solution is.

                  VRoninV Offline
                  VRoninV Offline
                  VRonin
                  wrote on last edited by
                  #8

                  @Taytoo said in Stream operators for subclassed QTreeWidgetItem not invoked:

                  Do I need separate Stream operators for ListEntry and ListEntry* ?

                  No, just for ListEntry*

                  Still would like to know what the proper solution is.

                  Depends on what ListEntry is in the context of your data model.
                  First question: why are you storing it as a pointer instead of a value in the model?

                  "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                  ~Napoleon Bonaparte

                  On a crusade to banish setIndexWidget() from the holy land of Qt

                  T 1 Reply Last reply
                  2
                  • T Taytoo

                    @kshegunov The module name is exe filename (which I wanted to hide).

                    Here's the subclassed item (I took out some private methods, since they're not related to this functionality)

                    class XItem : public QTreeWidgetItem {
                    public:
                    	friend QDataStream& operator<<(QDataStream& stream, const XItem & item);
                    	friend QDataStream& operator>>(QDataStream& stream, XItem & item);
                    
                    	XItem () { };
                    
                    	XItem (QTreeWidget* parent) :QTreeWidgetItem(parent) {}
                    
                    };
                    
                    Q_DECLARE_METATYPE(XItem );
                    

                    Overloaded Stream operators

                    QDataStream& operator<<(QDataStream& stream, const XItem& item)
                    {
                    	stream << item.text(0);
                    	return stream;
                    }
                    
                    QDataStream& operator>>(QDataStream& stream, XItem& item)
                    {
                    	QString text;
                    	stream >> text;
                    	item.setText(0, text);
                    
                    	return stream;
                    }
                    

                    This is the struct that is set as the DataRole

                    struct ListEntry
                    {
                    	int mapID = 0;
                    
                    	QString name;
                    	QDateTime dtModified;
                    };
                    

                    Here's how I'm setting the struct as DataRole

                    item->setData(iData, Qt::UserRole, QVariant::fromValue<ListEntry*>(&entry));
                    
                    kshegunovK Offline
                    kshegunovK Offline
                    kshegunov
                    Moderators
                    wrote on last edited by kshegunov
                    #9

                    @Taytoo said in Stream operators for subclassed QTreeWidgetItem not invoked:

                    Here's the subclassed item (I took out some private methods, since they're not related to this functionality)

                    That's fine, now we have at least something to work with. First, see what @VRonin wrote, and as an addition:

                    QVariant::fromValue<ListEntry*>(&entry)

                    Are you really wanting to save a pointer to an object? What I'd expect you to want to do is to serialize the struct itself, not a pointer to it that may or may not persist (the variant can have no way of knowing either way).

                    Edit: I just saw that @VRonin already mentioned this. Leaving the reply for posterity, though.

                    Read and abide by the Qt Code of Conduct

                    1 Reply Last reply
                    2
                    • VRoninV VRonin

                      @Taytoo said in Stream operators for subclassed QTreeWidgetItem not invoked:

                      Do I need separate Stream operators for ListEntry and ListEntry* ?

                      No, just for ListEntry*

                      Still would like to know what the proper solution is.

                      Depends on what ListEntry is in the context of your data model.
                      First question: why are you storing it as a pointer instead of a value in the model?

                      T Offline
                      T Offline
                      Taytoo
                      wrote on last edited by
                      #10

                      @VRonin said in Stream operators for subclassed QTreeWidgetItem not invoked:

                      @Taytoo said in Stream operators for subclassed QTreeWidgetItem not invoked:

                      Do I need separate Stream operators for ListEntry and ListEntry* ?

                      No, just for ListEntry*

                      What would the signatures of the stream operators for ListEntry* look like?

                      Still would like to know what the proper solution is.

                      Depends on what ListEntry is in the context of your data model.
                      First question: why are you storing it as a pointer instead of a value in the model?

                      It points to bunch of data related to the Item, doesn't make sense to serialize and store it all in the item, since there could be hundreds of items, so much faster to just get the pointer and access the values directly. That's why when serializing item, I don't need it either.

                      1 Reply Last reply
                      0

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved