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] Drag and drop a selection of cells in QTableWidget

[solved] Drag and drop a selection of cells in QTableWidget

Scheduled Pinned Locked Moved General and Desktop
4 Posts 2 Posters 5.5k Views
  • 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.
  • R Offline
    R Offline
    Rizokuri
    wrote on last edited by
    #1

    Hi,

    I have encountered a problem while trying to implement my own drag and drop in a QTableWidget:
    When the selection is overlapping with the dropping area, the items in the overlap are not moved... The other case works just fine (when my selection is not overlapping with the dropping area). I am testing on only 1 row now.

    I tried looking in the documentation and FAQ but it wasn't helpful.

    I reimplemented dragEnterEvent, dragMoveEvent and dropEvent like the following:

    @
    void dragEnterEvent(QDragEnterEvent * evt)
    {
    QByteArray oldbyteData = evt->encodedData( "application/x-qabstractitemmodeldatalist" );

    QDataStream stream( &oldbyteData, QIODevice::ReadOnly );

    kfSelection.clear();

    while( !stream.atEnd() )
    {
    IndexKf kf;
    QMap<int, QVariant> v;
    stream >> kf.layer >> kf.frame >> v;

    QTableWidgetItem* keyframe = item( kf.layer, kf.frame );
    if( keyframe == NULL )
    continue;
    kfSelection.push_back( kf );
    }

    if( kfSelection.size() == 0 )
    return;

    evt->acceptProposedAction();
    }

    void dragMoveEvent(QDragMoveEvent * evt)
    {
    evt->accept();
    }

    void dropEvent(QDropEvent *evt)
    {
    QByteArray oldbyteData = evt->encodedData( "application/x-qabstractitemmodeldatalist" );

    QDataStream stream( &oldbyteData, QIODevice::ReadOnly );

    for( std::vector<IndexKf>::iterator it = kfSelection.begin(); it != kfSelection.end(); ++it )
    {
    IndexKf kf = *it;

    QModelIndex newIdx = indexAt( evt->pos() );
    QTableWidgetItem* keyframe = takeItem( kf.layer, kf.frame );

    int newlayer = newIdx.row();
    int newframe = newIdx.column() - dragStartPosition.column() + kf.frame;

    setItem( newlayer, newframe, keyframe );
    }
    evt->acceptProposedAction();
    }
    @

    IndexKf is just a structure to store the row and column of the cells in my selection.

    I would appreciate any help and advices :)

    Thank you

    1 Reply Last reply
    0
    • G Offline
      G Offline
      giesbert
      wrote on last edited by
      #2

      Hi,

      you overwrite the items from 0 to end (where 0 is start of drop area).
      As you call setItem, you replace the old items.
      Might that be your problem?

      Nokia Certified Qt Specialist.
      Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

      1 Reply Last reply
      0
      • R Offline
        R Offline
        Rizokuri
        wrote on last edited by
        #3

        Hi,

        Thanks for the help, I modified my dropEvent function to this:

        @
        void dropEvent(QDropEvent *evt)
        {
        QByteArray oldbyteData = evt->encodedData( "application/x-qabstractitemmodeldatalist" );

        QDataStream stream( &oldbyteData, QIODevice::ReadOnly );

        QModelIndex newIdx = indexAt( evt->pos() );

        std::sort( kfSelection.begin(), kfSelection.end(), &IndexKf::sortIndexKf );

        int newframe = -1, newlayer = -1;
        QTableWidgetItem* tmp = NULL;
        for( std::vector<IndexKf>::iterator it = kfSelection.begin(); it != kfSelection.end(); ++it )
        {
        IndexKf kf = *it;

        newlayer = newIdx.row();
        newframe = newIdx.column() + (kf.frame - dragStartPosition.column());

        QTableWidgetItem* keyframe = (newframe==kf.frame)?tmp:takeItem( kf.layer, kf.frame ); // set to the deleted item if necessary
        tmp = takeItem( newlayer, newframe ); // take the item that is going to be deleted

        setItem( newlayer, newframe, keyframe );
        }
        evt->acceptProposedAction();
        }
        @

        Somehow it is still not working... I went through the debugger and the behaviour seemed correct. The item supposed to be dropped in the overlapping area is still not showing up after the drop.

        Edit: I think it is also interesting to note that dropping to an area overlapping with the original selection is not permitted in the original behaviour of QTableWidget. I can't figure out why though...

        1 Reply Last reply
        0
        • R Offline
          R Offline
          Rizokuri
          wrote on last edited by
          #4

          After taking a long break, I went back to check this code and finally found a solution.

          @
          void dragEnterEvent(QDragEnterEvent * evt)
          {
          QByteArray oldbyteData = evt->encodedData( "application/x-qabstractitemmodeldatalist" );

          QDataStream stream( &oldbyteData, QIODevice::ReadOnly );

          kfSelection.clear();

          while( !stream.atEnd() )
          {
          IndexKf kf;
          QMap<int, QVariant> v;
          stream >> kf.layer >> kf.frame >> v;

          kfSelection.push_back( kf );
          }

          if( kfSelection.size() == 0 )
          return;

          dragStartPosition = indexAt( evt->pos() );

          QTableWidget::dragEnterEvent( evt );
          }

          void dragMoveEvent(QDragMoveEvent * evt)
          {
          QTableWidget::dragMoveEvent( evt );
          }

          void dropEvent(QDropEvent *evt)
          {
          QModelIndex newIdx = indexAt( evt->pos() );

          int newframe, oldframe, layer;

          for( std::vector<IndexKf>::iterator it = kfSelection.begin(); it != kfSelection.end(); ++it )
          {
          (*it).item = takeItem( (*it).layer, (*it).frame );
          }

          for( std::vector<IndexKf>::iterator it = kfSelection.begin(); it != kfSelection.end(); ++it )
          {
          IndexKf kf = *it;
          layer = kf.layer;
          oldframe = kf.frame;
          newframe = newIdx.column() - dragStartPosition.column() + oldframe;

          setItem( layer, newframe, kf.item );
          }
          evt->setDropAction( Qt::IgnoreAction );
          }
          @

          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