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. [SOLVED, except the paint problem..] - DragDrop, QMimeData problem

[SOLVED, except the paint problem..] - DragDrop, QMimeData problem

Scheduled Pinned Locked Moved General and Desktop
15 Posts 2 Posters 4.4k Views 1 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.
  • M Offline
    M Offline
    maximus
    wrote on last edited by
    #1

    Hi,

    I am using QMimeData .userData() function to set a pointer to a custom object directly in a QMimeData object.
    This is working fine so far, but since I use that method, when I close my application, I got an error showing "Application stopped working", and I can't seem to find where this error come from. Is there a way to debug and know where this error come from? In the error log it says fault come from "Qt5Core.dll"

    I made a small video showing the error in action - "30sec video here":https://www.youtube.com/watch?v=SpFRHoehT3U&feature=youtu.be
    There are small bug in the interface that still needs fixing (problem with paint delegate..)
    Thanks if you can help me, If you need financial compensation I would gladly need an helper to finish this QListView model faster


    Free Indoor Cycling Software - https://maximumtrainer.com

    1 Reply Last reply
    0
    • M Offline
      M Offline
      maximus
      wrote on last edited by
      #2

      Here is my working delegate code: (except a paint problem that still need fixing)

      @#include "listintervaldelegate.h"
      #include <QDebug>
      #include "interval.h"
      #include "util.h"
      #include "intervalwidget.h"
      #include "edittargetpowerwidget.h"

      ListIntervalDelegate::ListIntervalDelegate(QObject parent) : QStyledItemDelegate(parent)
      {
      ptrParent = (QWidget
      )parent;
      }

      //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
      QWidget *ListIntervalDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const {

      IntervalWidget *widgetInterval = new IntervalWidget(parent);
      return widgetInterval;
      

      }

      //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
      void ListIntervalDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const {

      Interval interval = qvariant_cast<Interval>(index.model()->data(index, Qt::DisplayRole));
      IntervalWidget *widget = static_cast<IntervalWidget*>(editor);
      
      
      int stepType = interval.getType();
      QTime duration = interval.getDurationQTime();
      QString displayMsg = interval.getDisplayMessage();
      ///POWER
      int targetStepPower = interval.getPowerStepType();
      double startFTP = interval.getFTP_start() * 100;
      double endFTP = interval.getFTP_end() * 100;
      int range = interval.getFTP_range();
      
      
      widget->intervalComboBoxType->setCurrentIndex(stepType);
      widget->timeEdit->setTime(duration);
      widget->msgLineEdit->setText(displayMsg);
      ///POWER
      widget->stepTypeComboBoxPower->setCurrentIndex(targetStepPower);
      widget->targetStartValue->setValue(startFTP);
      widget->targetEndValue->setValue(endFTP);
      widget->targetRangeValue->setValue(range);
      

      }

      //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
      void ListIntervalDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const {

      IntervalWidget *widget = static_cast<IntervalWidget*>(editor);
      
      int stepTypeInt = widget->intervalComboBoxType->currentIndex();
      Interval::Type stepType = static_cast<Interval::Type>( stepTypeInt );
      QTime duration = widget->timeEdit->time();
      QString displayMsg = widget->msgLineEdit->text();
      ///POWER
      int targetStepPower = widget->stepTypeComboBoxPower->currentIndex();
      Interval::StepType stepTypePower = static_cast<Interval::StepType>( targetStepPower );
      double startFTP = widget->targetStartValue->value() / 100.0;
      double endFTP = widget->targetEndValue->value() / 100.0;
      int range = widget->targetRangeValue->value();
      
      
      
      Interval intervalTmp(duration, stepType, displayMsg,
                           stepTypePower, startFTP, endFTP, range,
                           stepTypePower, startFTP, endFTP, range,
                           stepTypePower, startFTP, endFTP, range);
      
      
      
      QVariant v = QVariant::fromValue(intervalTmp);
      model->setData(index, v, Qt::EditRole);
      

      }

      //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
      void ListIntervalDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {

      if(!index.isValid())
          return;
      
      
      bool paint = true;
      if (option.state & QStyle::State_Selected) {
          painter->fillRect(option.rect, option.palette.highlight());
      }
      
      
      if (paint) {
      
          painter->save();
          IntervalWidget *widget = new IntervalWidget(ptrParent);
          Interval interval = qvariant_cast<Interval>(index.model()->data(index, Qt::DisplayRole));
      
      
          int stepType = interval.getType();
          QTime duration = interval.getDurationQTime();
          QString displayMsg = interval.getDisplayMessage();
          ///POWER
          int targetStepPower = interval.getPowerStepType();
          double startFTP = interval.getFTP_start() * 100;
          double endFTP = interval.getFTP_end() * 100;
          int range = interval.getFTP_range();
      
          widget->intervalComboBoxType->setCurrentIndex(stepType);
          widget->timeEdit->setTime(duration);
          widget->msgLineEdit->setText(displayMsg);
          ///POWER
          widget->stepTypeComboBoxPower->setCurrentIndex(targetStepPower);
          widget->targetStartValue->setValue(startFTP);
          widget->targetEndValue->setValue(endFTP);
          widget->targetRangeValue->setValue(range);
      
      
          widget->resize( option.rect.size() );
          painter->translate(option.rect.topLeft());
          widget->render(painter, QPoint(), QRegion(), QWidget::DrawChildren );
      
          painter->restore();
          delete widget;
      }
      

      }

      //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
      void ListIntervalDelegate::updateEditorGeometry(QWidget editor, const QStyleOptionViewItem &option, const QModelIndex &/ index */) const {

      editor->setGeometry(option.rect);
      

      }

      QSize ListIntervalDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const {

      return QSize(500, 125); //enter your values here
      

      }
      @


      Free Indoor Cycling Software - https://maximumtrainer.com

      1 Reply Last reply
      0
      • M Offline
        M Offline
        maximus
        wrote on last edited by
        #3

        Here is my working ListModel code

        @#include "intervallistmodel.h"
        #include <QDebug>
        #include "streammyobject.h"

        IntervalListModel::IntervalListModel(QList<Interval> lstInterval, QObject *parent) : QAbstractListModel(parent) {
        this->lstInterval = lstInterval;
        }

        int IntervalListModel::rowCount(const QModelIndex &parent) const {

        Q_UNUSED(parent);
        return lstInterval.size();
        

        }

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////
        int IntervalListModel::columnCount(const QModelIndex &parent) const {

        Q_UNUSED(parent);
        return 1;
        

        }

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////
        QVariant IntervalListModel::headerData(int section, Qt::Orientation orientation, int role) const {

        if (role != Qt::DisplayRole)
            return QVariant();
        
        if (orientation == Qt::Horizontal)
            return QString("Column %1").arg(section);
        else
            return QString("Row %1").arg(section);
        

        }

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////
        QVariant IntervalListModel::data(const QModelIndex &index, int role) const {

        if (!index.isValid())
            return QVariant();
        
        if (index.row() >= lstInterval.size() || index.row() < 0)
            return QVariant();
        
        
        if (role == Qt::DisplayRole || role == Qt::EditRole) {
        
            Interval interval = lstInterval.at(index.row());
            QVariant v = QVariant::fromValue(interval);
            return v;
        
        }
        else {
            return QVariant();
        }
        

        }

        bool IntervalListModel::insertRows(int position, int rows, const QModelIndex &index) {

        Q_UNUSED(index);
        beginInsertRows(QModelIndex(), position, position + rows - 1);
        
        qDebug() << "INSERT ROW";
        
        for (int row = 0; row < rows; ++row) {
        
            QTime time1(0, 5, 0);
            Interval interval(time1, Interval::INTERVAL, "display_msg",
                              Interval::FLAT, .50, .50, 20,
                              Interval::FLAT, 100, 100, 15,
                              Interval::FLAT, .60, .60, 50);
            lstInterval.insert(position, interval);
        }
        
        endInsertRows();
        return true;
        

        }

        bool IntervalListModel::removeRows(int position, int rows, const QModelIndex &index)
        {
        Q_UNUSED(index);
        beginRemoveRows(QModelIndex(), position, position + rows - 1);

        qDebug() << "REMOVE ROW";
        
        for (int row = 0; row < rows; ++row) {
            lstInterval.removeAt(position);
        }
        
        endRemoveRows();
        return true;
        

        }

        bool IntervalListModel::setData(const QModelIndex &index, const QVariant &value, int role)
        {

        qDebug() << "SET DATA";
        
        if (index.isValid() && role == Qt::EditRole) {
        
            Interval interval = qvariant_cast<Interval>(value);
            lstInterval.replace(index.row(), interval);
            emit dataChanged(index, index);
            return true;
        }
        
        return false;
        

        }

        Qt::ItemFlags IntervalListModel::flags(const QModelIndex &index) const
        {

        Qt::ItemFlags defaultFlags = QAbstractListModel::flags(index);
        
        if (index.isValid())
            return Qt::ItemIsDragEnabled | Qt::ItemIsEditable |defaultFlags;
        else
            return Qt::ItemIsDropEnabled | defaultFlags;
        

        }

        QStringList IntervalListModel::mimeTypes() const {

        QStringList types;
        types << "maxtrainer/interval";
        return types;
        

        }

        bool IntervalListModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) {

        qDebug() << "DROPMINEDATA";
        
        if (action == Qt::IgnoreAction)
            return true;
        
        if (!data->hasFormat("amaxtrainer/interval"))
            return false;
        
        if (column > 0)
            return false;
        int beginRow;
        
        if (row != -1)
            beginRow = row;
        else if (parent.isValid())
            beginRow = parent.row();
        else
            beginRow = rowCount(QModelIndex());
        
        QByteArray encodedData = data->data("maxtrainer/interval");
        QDataStream stream(&encodedData, QIODevice::ReadOnly);
        StreamMyObject myStreamer;
        Interval interval;
        
        while (!stream.atEnd()) {
            /// Deserialize stream into Object
            Util::operator >>(stream, interval);
            myStreamer.operator >>(stream, interval);
        }
        
        insertRow(beginRow, QModelIndex());
        
        QModelIndex idx = index(beginRow, 0, QModelIndex());
        QVariant v = QVariant::fromValue(interval);
        setData(idx, v);
        
        
        return true;
        

        }

        QMimeData *IntervalListModel::mimeData(const QModelIndexList &indexes) const {

        qDebug() << "MIME_DATA";
        
        QMimeData *mimeData = new QMimeData();
        QByteArray encodedData;
        
        StreamMyObject myStreamer;
        QDataStream stream(&encodedData, QIODevice::WriteOnly);
        
        foreach (QModelIndex index, indexes) {
            if (index.isValid()) {
                Interval interval = qvariant_cast<Interval>(data(index, Qt::DisplayRole) );
                ///Write object to the stream (serialize)
                myStreamer.operator <<(stream, interval);
            }
        }
        
        mimeData->setData("maxtrainer/interval", encodedData);
        return mimeData;
        

        }

        Qt::DropActions IntervalListModel::supportedDropActions() const {

        return Qt::MoveAction;
        

        }@


        Free Indoor Cycling Software - https://maximumtrainer.com

        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          Hi,

          Do you really need to have your Interval has pointers ? How do you store them in the first place ?

          @
          if (option.state & QStyle::State_Selected) {
          painter->fillRect(option.rect, option.palette.highlight());
          paint = false; <--- here is the cause
          }

          if (paint) { <--- there

              painter->save();
              IntervalWidget *widget = new IntervalWidget(ptrParent);
          

          @

          You are setting paint to false when selected thus the code doing the rendering will not be called

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          0
          • M Offline
            M Offline
            maximus
            wrote on last edited by
            #5

            Thanks for the reply SGaist,
            My interval are stored in the IntervalListModel has "QList<Interval*> lstInterval;"

            If I remove the check for painting with State_Selected in paint(), the widget will be rendered 2 times, in createEditor() and paint(), resulting in a weird double widget interface when i'm in edit mode (double clicked on a row)

            [Edit: I changed QList<Interval*> for QList<Interval> and all my memory management problem are gone, QList does the job for me]


            Free Indoor Cycling Software - https://maximumtrainer.com

            1 Reply Last reply
            0
            • M Offline
              M Offline
              maximus
              wrote on last edited by
              #6

              edited


              Free Indoor Cycling Software - https://maximumtrainer.com

              1 Reply Last reply
              0
              • SGaistS Offline
                SGaistS Offline
                SGaist
                Lifetime Qt Champion
                wrote on last edited by
                #7

                Then there's no need to play with pointers with that class.

                For the painting problem I might have misunderstood. What is happening now ?

                Interested in AI ? www.idiap.ch
                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                1 Reply Last reply
                0
                • M Offline
                  M Offline
                  maximus
                  wrote on last edited by
                  #8

                  Forgive me but I haven't figured how to edit the model internal data without having a pointer to Interval* in each QVariant QModelIndex.
                  Since my editor Widget edit all the fields of the Interval object at the same time, I cannot use the standard approach with (1 widget = 1 object attribute field edit, like spinboxDelegate example)

                  The painting problem now :
                  https://www.youtube.com/watch?v=-XLK1UW6uM8&feature=youtu.be&hd=1

                  Thanks for your time

                  Max
                  http://maximumtrainer.com/


                  Free Indoor Cycling Software - https://maximumtrainer.com

                  1 Reply Last reply
                  0
                  • SGaistS Offline
                    SGaistS Offline
                    SGaist
                    Lifetime Qt Champion
                    wrote on last edited by
                    #9

                    Exactly the same as currently (well, without pointers), and in the model you replace the Interval in the list with the one you just created

                    Interested in AI ? www.idiap.ch
                    Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                    1 Reply Last reply
                    0
                    • M Offline
                      M Offline
                      maximus
                      wrote on last edited by
                      #10

                      Thanks, you made me realize that a QList of pointer is not the way to go.
                      I replaced my model data QList<*Interval> with QList<Interval> and let QList manage memory much easier this way!

                      Still got the paint problem in double though (as you can see in video from previous post)

                      Merci!


                      Free Indoor Cycling Software - https://maximumtrainer.com

                      1 Reply Last reply
                      0
                      • M Offline
                        M Offline
                        maximus
                        wrote on last edited by
                        #11

                        I created a new thread "here":http://qt-project.org/forums/viewthread/37501/ for serialization of a customObject in QMimeData. Also edited the code up there with the latest working code
                        Thank you


                        Free Indoor Cycling Software - https://maximumtrainer.com

                        1 Reply Last reply
                        0
                        • SGaistS Offline
                          SGaistS Offline
                          SGaist
                          Lifetime Qt Champion
                          wrote on last edited by
                          #12

                          You could try to detect QStyle::State_Editing and not paint in that case.

                          I would also recommend keeping an IntervalWidget as member variable in your delegate only for the painting purpose, that would avoid recreating the widget each time you have to render it.

                          Interested in AI ? www.idiap.ch
                          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                          1 Reply Last reply
                          0
                          • M Offline
                            M Offline
                            maximus
                            wrote on last edited by
                            #13

                            I used your suggestion, one widget created in delegate constructor and deleted in destructor, thanks

                            As for QStyle::State_Editing, the state never get triggered it seems, can I force the state myself in the createEditor() function or something? I could just have a simple flag when I know item is being edited, and don't paint in that case.

                            I created another tread for the paint problem, as well as a rant on the QDelegate -_-
                            http://qt-project.org/forums/viewthread/37513/


                            Free Indoor Cycling Software - https://maximumtrainer.com

                            1 Reply Last reply
                            0
                            • M Offline
                              M Offline
                              maximus
                              wrote on last edited by
                              #14

                              Hey SGaist it's me again.

                              Do you think a QListWidget would work in my use-case
                              Is drag and drop possible in a QListWidget?
                              I still haven't figured this paint problem with the delegate..
                              Thank you,..


                              Free Indoor Cycling Software - https://maximumtrainer.com

                              1 Reply Last reply
                              0
                              • SGaistS Offline
                                SGaistS Offline
                                SGaist
                                Lifetime Qt Champion
                                wrote on last edited by
                                #15

                                Drag and drop is possible with all model/view classes whether it's a QTableView or QListView. The setup will differ between the widget and view version that's all.

                                Interested in AI ? www.idiap.ch
                                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                                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