[SOLVED]How to delete an item from the treeview by droping an item to pushbutton or to an group box



  • I have a treeview where the items are listed (say item 1 to item 10) and for each item (say item 1 )there are some subitem (say item11 to item 19) . I have a pushbutton "Delete items" which deletes the root item when psuhbutton is pressed (item1). Now i want to implement using drag and drop . Is it possible to drag item and drop the item to pushbutton "delete items" so that the root item deletes along with subitem ??
    Adjacent to treeview there is a group box (group box has lineedit ,combobox, label etc). Is it possible to drag item and drop the item to groupbox so that the root item deletes along with subitem ???


  • Qt Champions 2016

    Hi
    Yeah that should be possible
    if you set setAcceptDrops(true);
    for your mainwind/dialog
    and then handle
    void Window::dragMoveEvent(QDragMoveEvent *event)
    and
    void Window::dropEvent(QDropEvent *event)

    I think if you set the action to move, the Tree will remove it when
    drop triggers but not sure.
    Else you just need to do when you do when button is clicked.

    Look here for info about drag/drop
    http://www.informit.com/articles/article.aspx?p=1405546

    Note: Entire window will be drop target so in DragMove event they seems to do
    if (event->answerRect().intersects(dropFrame->geometry()))
    to check if it was over the wanted area. In this case a frame but could be button.



  • @mrjj
    Thanks for the reply .
    I have set setAcceptDrops(true); ui->treeView->setAcceptDrops(true);
    and created void Window::dragMoveEvent(QDragMoveEvent *event)
    and
    void Window::dropEvent(QDropEvent *event)

    void Window::dragMoveEvent(QDragMoveEvent *event)
    {
        Window *source = qobject_cast<Window *>(event->source());
        if (source && source != this) {
            event->setDropAction(Qt::MoveAction);
            event->accept();
        }
    }
    void Window::dropEvent(QDropEvent *event)
    {
        Window *source =qobject_cast<Window *>(event->source());
        if (source && source != this)
        {
            event->setDropAction(Qt::MoveAction);
            event->accept();
        }
    }
    

    I am unaware of how to set condition .


  • Qt Champions 2016

    @Ratzz said:

    Hmm. Maybe I misunderstood you,

    You want to drag from the tree to outside. ?
    so ui->treeView->setAcceptDrops(true);
    tells treeview it can be drop target. ( dropped on)
    Should also tell you MainWindow
    so Window (which is your mainwindow ? )
    Normally it would be named MainWindow but if Window is you mainwin then all fine.

    "set condition " ?
    you mean
    if (event->answerRect().intersects(dropFrame->geometry()))
    or ?



  • @mrjj
    Yes , I want to drag the item from the tree to outside and to pushbutton "Delete item".
    I have to set setAcceptDrops(true); to pushbutton and groupbox area right?
    yes i meant if (event->answerRect().intersects(dropFrame->geometry()))


  • Qt Champions 2016

    Ok so your mainwindow is the drop target
    and you should call etAcceptDrops(true); in constructor.

    and this line
    if (event->answerRect().intersects(dropFrame->geometry()))

    should be used to check its actually dropped on the button.
    dropFrame should just be the name of your delete button.
    It says if the Area for the drop is within the dropFrame Area.
    as it , "dropped on the frame"

    sosomething like

    void (Main?)Window::dropEvent(QDropEvent *event)
    {
        Window *source =qobject_cast<Window *>(event->source());
        if (source && source != this &&  
         (event->answerRect().intersects(ui->ThatButton->geometry())))
        {
            event->setDropAction(Qt::MoveAction);
            event->accept();
        }
    

    All "Window" should be "MainWindow" in case its normal project. Unless you did
    rename name it to Window yourself :)



  • @mrjj
    Is the answerRect() member of QDropevnt(); ?
    Because i get error

     error: 'class QDropEvent' has no member named 'answerRect'
    (event->answerRect().intersects(ui->pushButton_DeleteMinorFrame->geometry())))
             ^

  • Qt Champions 2016

    @Ratzz said:

    event->answerRect()

    Hi. sorry my bad. its part of QDragMoveEvent
    so should check in ::dragMoveEvent instead.


  • Lifetime Qt Champion

    Hi,

    Wouldn't it be simpler to subclass QPushButton and add the drag'n'drop logic directly in it ?


  • Qt Champions 2016

    @SGaist
    Yeah that is also an option , but since normally you already have a QMainWindow
    subclass, i thought it could be slightly faster to add
    and would work with most widgets after.



  • @mrjj
    Adding event dragMoveEvent will work ??
    Should not i add QDropevnt() ??

    void MyWindow::dragMoveEvent(QDragMoveEvent *event)
    {
          MyWindow *source =qobject_cast<MyWindow *>(event->source());
        if (source && source != this &&
         (event->answerRect().intersects(ui->pushButton_Delete->geometry())))
        {
            event->setDropAction(Qt::MoveAction);
            event->accept();
        }
    }
    

    I added the above but did not .



  • @SGaist
    How to subclass QPushButton and add the drag'n'drop logic directly in it ??


  • Lifetime Qt Champion

    The same you would any other widget. Take a look at the Drag And Drop chapter in Qt's documentation



  • @SGaist
    As suggested by @mrjj should i add QDropevnt()??
    how will the dragMoveEvent come to know that i have to delete ?? Just dragging to pushButton_Delete will work??
    When to call slot of deleting items??


  • Qt Champions 2016

    @Ratzz
    Hi yes you would still need the DropEvent.

    This works with ListWidget with dragDrop mode set to DragOnly.
    Since the DropAction is "move", it did remove the item from the list.
    Your result may vary.

    #ifndef DROPBUTTON_H
    #define DROPBUTTON_H
    
    #include <QPushButton>
    #include <QDragMoveEvent>
    
    class DropButton : public QPushButton {
      Q_OBJECT
     public:
      explicit  DropButton(QWidget* parent = 0) : QPushButton(parent) {
        setAcceptDrops(true);
      }
     protected:
      void dragEnterEvent(QDragEnterEvent* event) {
        event->acceptProposedAction();
      }
    
      void dropEvent(QDropEvent* event) {
        event->setDropAction(Qt::MoveAction);
        event->accept();
      }
    };
    
    #endif // DROPBUTTON_H
    


  • @mrjj
    I tried this

    #include <QDragMoveEvent>
    #include <QDropEvent>
    protected:
        void dragMoveEvent(QDragMoveEvent *event);
        void dropEvent(QDropEvent *event);
    
    ui->pushButton_DeleteMinorFrame->setAcceptDrops(true);
    
    void Window::dragMoveEvent(QDragMoveEvent *event)
    {
        Window *source =qobject_cast<Window *>(event->source());
        if (source && source != this &&
                (event->answerRect().intersects(ui->pushButton_DeleteMinorFrame->geometry())))
        {
            event->acceptProposedAction();
        }
    }
    
    void Window::dropEvent(QDropEvent *event)
    {
        event->setDropAction(Qt::MoveAction);
        event->accept();
    }
    

    But above does not work for me. Where did i miss??
    Control does not come to these function dragMoveEvent/dropEvent when i drag and drop


  • Qt Champions 2016

    Hi you have to use the Dropbutton also.

    That is why I though using Mainwindow would be easier.

    Best way to do that is to use the promote feature.

    1. save the code in a file called dropbutton.h
      (just to be safe, also create dropbutton.cpp as empty)
    2. right click on your button you want to be a drop button.
      Select "Promote To..."
      In "Promoted classname" type
      DropButton
      (case Matters!)
      in
      header file : type
      dropbutton.h
      Then click "Add" and then Promote.
      Now when you run the program, the normal buttons becomes the DropButton.


  • Thanks mates



  • @mrjj
    Yes, i Tried you code which turns out to be a Dropbutton. How to implement it in my code ?


  • Qt Champions 2016

    @Ratzz
    As I wrote in answer ?
    Using the promote feature.
    Which will runtime replace a normal button with the DropButton.
    Or you can new a button you self
    Like
    Dropbutton *but=Dropbutton (this)
    and insert into your window/layout.



  • @mrjj
    Yes its working now fine..
    I have group box adjacent to treeview. Can i implement the same to groupbox?


  • Qt Champions 2016

    @Ratzz
    Super.
    Well If you promote the GroupBox, there might be issue with
    Parent. I have never tried it.
    Try it :)
    If it says funny stuff , just demote it to a groupbox again.

    Else its pretty much the same, except new filename and new name.

    #include <QGroupBox>
    #include <QDragMoveEvent>
    
    class DropGroupBox : public QGroupBox {
      Q_OBJECT
     public:
      explicit  DropGroupBox(QWidget* parent = 0) : QGroupBox(parent) {
        setAcceptDrops(true);
      }
     protected:
      void dragEnterEvent(QDragEnterEvent* event) {
        event->acceptProposedAction();
      }
    
      void dropEvent(QDropEvent* event) {
        event->setDropAction(Qt::MoveAction);
        event->accept();
      }
    };
    


  • @mrjj
    i promoted the group using Qpushbutton but not allow me to promote the GroupBox. so i added dropgroupBox.h and promoted it.
    But its not working.


  • Qt Champions 2016

    @Ratzz
    Hi
    Something must gone wrong. maybe.
    Tried it here and it does accept drops

    https://www.dropbox.com/s/7bkqatzm6vt1kmz/promotedgb.zip?dl=0


  • Lifetime Qt Champion

    Out of curiosity… Why are you creating so many widgets that should allow to delete items from your view using dnd ? It doesn't feel very intuitive nor following the guidelines of major OSs



  • @mrjj
    Yes your code is working . But do not know in my case its not working .
    You have used Listwidget and i have used list view . Does it matters??



  • @SGaist
    Yes , My treeview is in between listview and groupbox . even if the listview items are dragged to the pushbutton_delete its getting deleted. which in my case should not. what is the best way to do ??


  • Lifetime Qt Champion

    Implement it in one of the usual ways:

    • React to the delete or backspace key
    • Have a delete button that will delete the currently selected row/column etc.
    • Have a dedicated column with e.g. a QPushButton to delete the row completely.


  • @SGaist
    I already have a delete button which deletes entire row.



  • @mrjj
    The code you shared is working (group box).


  • Qt Champions 2016

    @Ratzz
    Ok. super.



  • @mrjj
    But now i can drag items from treeview as well as listview to pushbutton and groupbox. But i do not want the user to allow listview items to dragged to pushbutton/groupbox


  • Qt Champions 2016

    @Ratzz
    Hmm maybe you can check with
    sender();
    in dragEnterEvent
    and if its the not a Treeview then reject the drop

    like

    QTreeView* theone= dynamic_cast<QTreeView*>(sender());
       if( theone!= NULL ) 
       { 
          event->acceptProposedAction();
       }
    


  • @mrjj
    I do not have dragEnterEvent event yet! . we have a custom event using dropMimeData .


  • Qt Champions 2016

    @Ratzz
    how does this custom event look like ?

    and its not an options just to disable Drag from listview?



  • @mrjj
    All drag drop events are handled in this. I am not aware how Bec, previous programmer has done it.

    bool MessageModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
    {
        if(action == Qt::CopyAction)
        {
    //        QStringList format = data->formats();
            QByteArray encodedData = data->data("application/x-qabstractitemmodeldatalist");
            QDataStream stream(&encodedData, QIODevice::ReadOnly);
            QMap<int,  QVariant> roleDataMap;
    //        roleDataMap.setInsertInOrder(true);
            QMap<int, QString> sortMsgs;
    
            while (!stream.atEnd())
            {
                int row, col;
                stream >> row >> col >> roleDataMap;
                QString tmp = roleDataMap.value(0).toString();
                //MsgId1.append(tmp);
                sortMsgs.insert(row,tmp);
            }
            QList < QString > MsgId1 = sortMsgs.values();
    
            if(parent.parent().isValid() && !parent.parent().parent().isValid())
            {
                QStandardItemModel::dropMimeData(data,action,row,column,parent);
                emit addFrameMessageIds(parent.row(), -1, MsgId1);
                return true;
            }
            if(parent.parent().parent().isValid() && column == -1)
            {
                QStandardItemModel::dropMimeData(data,action,parent.row() +1,column,parent.parent());
                emit addFrameMessageIds(parent.parent().row(),parent.row() +1, MsgId1);
                return true;
            }
            if(parent.parent().parent().isValid() && column == 0)
            {
                QStandardItemModel::dropMimeData(data,action,row,column,parent);
                emit addFrameMessageIds(parent.row(), row, MsgId1);
                return true;
            }
        }
        else if(action == Qt::MoveAction)
        {
            if(!parent.isValid())
            {
                return QStandardItemModel::dropMimeData(data,action,indexesLocal.row(),indexesLocal.column(),indexesLocal.parent());
            }
            if(indexesLocal.parent().parent().isValid() && !parent.parent().isValid() && column == -1)
            {
                //Msg is dropped on major frame
                return QStandardItemModel::dropMimeData(data,action,indexesLocal.row(),indexesLocal.column(),indexesLocal.parent());
            }
            if(indexesLocal.parent().parent().isValid() && !parent.parent().parent().isValid() && column == -1)
            {
                //Msg is dropped on minor frame
                if(indexesLocal.parent().row() != parent.row())
                {
                    QStandardItemModel::dropMimeData(data,action,row,column,parent);
                    emit moveFrameMessageIds(indexesLocal.parent().row(),parent.row(),indexesLocal.row(),-1);
                    return true;
                }
                else
                {
                    QStandardItemModel::dropMimeData(data,action, 0 ,column,parent);
                    emit moveFrameMessageIds(indexesLocal.parent().row(),parent.row(),indexesLocal.row(),0);
                    return true;
                }
            }
            if(indexesLocal.parent().parent().isValid() && parent.parent().parent().isValid() && column == -1)
            {
                //      Msg is dropped on another msg
                QStandardItemModel::dropMimeData(data,action,parent.row()+1,column,parent.parent());
                emit moveFrameMessageIds(indexesLocal.parent().row(),parent.parent().row(),indexesLocal.row(),parent.row()+1);
                return true;
            }
            if(indexesLocal.parent().isValid() && !(indexesLocal.parent().parent().isValid()) && !parent.parent().isValid() && column == -1)
            {
                //      Minor frame is dropped on Major frame
                QStandardItemModel::dropMimeData(data,action,0,indexesLocal.column(),indexesLocal.parent());
                emit moveFrame(indexesLocal.row(),0);
                return true;
            }
            if(indexesLocal.parent().isValid() && !(indexesLocal.parent().parent().isValid()) && parent.parent().isValid() && !(parent.parent().parent().isValid()) && column == -1)
            {
                // Minor frame is dropped on another minor frame
                int pre = indexesLocal.row();
                int cur = parent.row();
                QStandardItemModel::dropMimeData(data,action,parent.row()+1,column,parent.parent());
                emit moveFrame(indexesLocal.row(),parent.row());
                return true;
            }
            if(indexesLocal.parent().isValid() && !(indexesLocal.parent().parent().isValid()) && parent.parent().parent().isValid() && column == -1)
            {
                return QStandardItemModel::dropMimeData(data,action,indexesLocal.row(),indexesLocal.column(),indexesLocal.parent());
                //      Minor frame is dropped on msg
            }
            if(indexesLocal.parent().isValid() && !(indexesLocal.parent().parent().isValid()) && !parent.parent().isValid() && column == 0)
            {
                QStandardItemModel::dropMimeData(data,action,row,indexesLocal.column(),indexesLocal.parent());
                emit moveFrame(indexesLocal.row(),row);
                return true;
                //      Minor frame is dropped after minor
            }
            if(indexesLocal.parent().isValid() && !(indexesLocal.parent().parent().isValid()) && !parent.parent().parent().isValid() && column == 0)
            {
                return QStandardItemModel::dropMimeData(data,action,indexesLocal.row(),indexesLocal.column(),indexesLocal.parent());
                //      Minor frame is dropped after msg
            }
            if(indexesLocal.parent().parent().isValid() && parent.isValid() && !parent.parent().isValid() && column == 0)
            {
                return QStandardItemModel::dropMimeData(data,action,indexesLocal.row(),indexesLocal.column(),indexesLocal.parent());
                //      Msg is dropped after minor
            }
            if(indexesLocal.parent().parent().isValid() && parent.parent().isValid() && !parent.parent().parent().isValid() && column == 0)
            {
                QStandardItemModel::dropMimeData(data,action,row,parent.column(),parent);
                emit moveFrameMessageIds(indexesLocal.parent().row(),parent.row(),indexesLocal.row(),row);
                return true;
                //      Msg is dropped after msg
            }
    }
    }
    

    And one more thing. If i drag items to pushbutton/group box the listview count is not getting updated.. ex:if i have 5 items and drag 1 item to pushbutton_delete then the count will be 5 . if i manually press delete button now then the list is getting updated to 3.


  • Qt Champions 2016

    @Ratzz said:

    But i do not want the user to allow listview items to dragged to pushbutton/groupbox

    So why can you not check there ?

    also
    http://doc.qt.io/qt-5/qtreewidget.html#dropMimeData
    Seems to be when something is dropped on Tree and im confused what it has to do with the
    Groupbox ?



  • @mrjj
    Since the groupbox is deletes item as you suggested it also deletes listview items when dragged.


  • Qt Champions 2016

    @Ratzz
    And the DragGBox do have
    void dragEnterEvent(QDragEnterEvent* event) {
    event->acceptProposedAction();
    }

    So why cant you just check that sender if the accepted one and then acccept or if not then
    reject the drop?



  • @mrjj
    dragEnterEvent shoud be used for main class?


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.