2

i want to hide the "dragging indicator"(the dragged row screenshot) only show mouse arrow when dragging in QTreeWidget, is it possible?

i tried to reimplement mouseMoveEvent, the "dragging indicator" went away but at the same time , drag/drop is disabled, what am i missing

code:

#!/usr/bin/env python2
import os
import sys
import re

from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import Qt, QString


class MyTreeWidget(QtGui.QTreeWidget):

    def mouseMoveEvent_xxx(self, e):
        mimeData = QtCore.QMimeData()
        drag = QtGui.QDrag(self)
        drag.setMimeData(mimeData)

        # pixmap = QtGui.QPixmap()
        # drag.setPixmap(pixmap)

        # drag.setHotSpot(e.pos())

        # QtGui.QTreeWidget.mouseMoveEvent(self,e)
        drag.exec_(QtCore.Qt.MoveAction)


    def dropEvent(self,e):
        QtGui.QTreeWidget.dropEvent(self,e)
        self.expandAll()
        e.accept()



class TheUI(QtGui.QDialog):

    def __init__(self, args=None, parent=None):
        super(TheUI, self).__init__(parent)
        self.layout = QtGui.QVBoxLayout(self)
        treeWidget = MyTreeWidget()

        button = QtGui.QPushButton('Add')
        self.layout.addWidget(treeWidget)
        self.layout.addWidget(button)
        treeWidget.setHeaderHidden(True)

        self.treeWidget = treeWidget
        self.button = button
        self.button.clicked.connect(lambda *x: self.addCmd())

        HEADERS = ( "script", "chunksize", "mem" )
        self.treeWidget.setHeaderLabels(HEADERS)
        self.treeWidget.setColumnCount( len(HEADERS) )

        self.treeWidget.setColumnWidth(0,160)
        self.treeWidget.header().show()

        self.treeWidget.setDragDropMode(QtGui.QAbstractItemView.InternalMove)

        self.resize(500,500)
        for i in xrange(6):
            item =self.addCmd(i)
            if i in (3,4):
                self.addCmd('%s-1' % i,parent=item)

        self.treeWidget.expandAll()
        self.setStyleSheet("QTreeWidget::item{ height: 30px;  }")

    def addCmd(self, i,parent=None):
        'add a level to tree widget'

        root = self.treeWidget.invisibleRootItem()
        if not parent:
            parent=root
        item = QtGui.QTreeWidgetItem(parent,['script %s' %i,'1','150'])
        return item

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    gui = TheUI()
    gui.show()
    app.exec_()

screenshot:

enter image description here

i want to hide the blue dragged bar, while keeping the mouse arrow.( or give it some custom pixmap, or better draw an dotted outline around the dragged bar), the idea being not want to obscure the tree content behind it, ( in my system comopositing manager is disabled, so semi transparency is impossible )

if you rename mouseMoveEvent_xxx to mouseMoveEvent, you will see what i meant, dragging is disabled, although i've set dragDropMode to InternalMove

Nilesh
  • 20,521
  • 16
  • 92
  • 148
Shuman
  • 3,914
  • 8
  • 42
  • 65

1 Answers1

3

Very interesting !

I have find behavior of drag indicator in Qt 4 (C++). At last, I found method void QAbstractItemView::startDrag(Qt::DropActions supportedActions) is control start drag and drag indicator. At Line 3217 - 3238 is can tell behavior of drag and line 3229 is it your want (Set new image or no set it). OK, solution is find any way to put that line 3229 it out or replace new image it. Absolutely, We must to override this method. But, new problem is it C++ and your use in python. We have to change something to put it in python can can doing work. (Hardcore ...)

OK, This is it. Override method QAbstractItemView.startDrag (self, Qt.DropActions supportedActions);

from C++;

    .
    .
    .
void QAbstractItemView::startDrag(Qt::DropActions supportedActions)
{
Q_D(QAbstractItemView);
QModelIndexList indexes = d->selectedDraggableIndexes();
if (indexes.count() > 0) {
    QMimeData *data = d->model->mimeData(indexes);
    if (!data)
        return;
    QRect rect;
    QPixmap pixmap = d->renderToPixmap(indexes, &rect);
    rect.adjust(horizontalOffset(), verticalOffset(), 0, 0);
    QDrag *drag = new QDrag(this);
    drag->setPixmap(pixmap);
    drag->setMimeData(data);
    drag->setHotSpot(d->pressedPosition - rect.topLeft());
    Qt::DropAction defaultDropAction = Qt::IgnoreAction;
    if (supportedActions & Qt::CopyAction && dragDropMode() != QAbstractItemView::InternalMove)
        defaultDropAction = Qt::CopyAction;
    if (drag->exec(supportedActions, defaultDropAction) == Qt::MoveAction)
        d->clearOrRemove();
    }
}
    .
    .
    .

To python;

class QCustomTreeWidget (QtGui.QTreeWidget):
    .
    .
    .
    def startDrag (self, supportedActions):
        listsQModelIndex = self.selectedIndexes()
        if listsQModelIndex:
            dataQMimeData = self.model().mimeData(listsQModelIndex)
            if not dataQMimeData:
                return None
            dragQDrag = QtGui.QDrag(self)
            # dragQDrag.setPixmap(QtGui.QPixmap('test.jpg')) # <- For put your custom image here
            dragQDrag.setMimeData(dataQMimeData)
            defaultDropAction = QtCore.Qt.IgnoreAction
            if ((supportedActions & QtCore.Qt.CopyAction) and (self.dragDropMode() != QtGui.QAbstractItemView.InternalMove)):
                defaultDropAction = QtCore.Qt.CopyAction;
            dragQDrag.exec_(supportedActions, defaultDropAction)

Experimental result

I test this code and implemented code, Work fine. But, I can't capture picture during drag indicator. (I use windows 7)


Useful reference : QDrag Class Reference, QAbstractItemView


Bandhit Suksiri
  • 3,390
  • 1
  • 18
  • 20