I have a Widget window contains two QtTree Widgets. It works fine when I drag and drop items from one tree widget to another tree widget. But If I drag an item and drop it to the same tree widget (which is not a desired behavior, so I disable accept drop in the code), the Tree Widget ignore my next mouse press event.
To reproduce the issue, please run the code and
1.Drag an item from the left tree and drop it the same tree widget.
2.Click any item on the left tree widget, and you will notice nothing change
3.Click same or other item again, and the selection changes.
also, try click the small expend icon after drop an item. No matter how many time you click on the small expend icon, no events.
from PyQt4 import QtGui, QtCore
import cPickle
class MyTreeItem(QtGui.QTreeWidgetItem):
def __init__(self, parent=None):
super(MyTreeItem, self).__init__(parent)
self.setFlags(QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsDropEnabled)
def getPath(self):
"""
Rebuild path from the tree.
"""
if isinstance(self.parent(), MyTreeItem):
path = '{0}/{1}'.format(self.parent().getPath() ,str(self.text(0)))
#The top level item
else:
path = '/{0}'.format(str(self.text(0)))
return path
def getParents(self):
"""
Get all the parents to the top level.
"""
parents = []
while self:
self = self.parent()
if isinstance(self, MyTreeItem):
parents.append(self)
return parents
def getChildren(self):
"""
Get all the children(flatten).
"""
children = []
if not self:
return children
childrenCount = self.childCount()
if childrenCount == 0:
return children
for idx in range(childrenCount):
citem = self.child(idx)
if citem:
children.append(citem)
children.extend(citem.getChildren())
return children
class MyTreeWidget(QtGui.QTreeWidget):
def __init__(self, parent = None):
super(MyTreeWidget, self).__init__(parent)
self.setDragEnabled(True)
self.setAcceptDrops(True)
self.setHeaderLabels(["Select Members"])
self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
self.mousePressPos = QtCore.QPoint(0,0)
def mousePressEvent(self, event):
super(MyTreeWidget, self).mousePressEvent(event)
#if event.button() == QtCore.Qt.LeftButton:
# self.mousePressPos = event.pos()
def mouseMoveEvent(self, event):
super(MyTreeWidget, self).mouseMoveEvent(event)
#length = (event.pos() - self.mousePressPos).manhattanLength()
#if length < QtGui.QApplication.startDragDistance():
# return
self.setAcceptDrops(False)
drag = QtGui.QDrag(self)
mime_data = QtCore.QMimeData()
passme = []
for sel in self.selectedItems():
dnddict = {}
dnddict['disp'] = sel.getPath()
dnddict['val'] = sel.getPath()
passme.append(dnddict)
bstream = cPickle.dumps(passme)
mime_data.setData("application/x-ltreedata", bstream)
drag.setMimeData(mime_data)
self.setAcceptDrops(True)
action = drag.exec_()
def mouseReleaseEven(self, event):
self.setAcceptDrop(True)
event.accept()
def dragMoveEvent(self, event):
if event.mimeData().hasFormat("application/x-ltreedata"):
event.accept()
else:
event.ignore()
def dragEnterEvent(self, event):
if event.mimeData().hasFormat("application/x-ltreedata"):
event.accept()
else:
event.ignore()
def dropEvent(self, event):
if event.source() == self:
event.ignore()
else:
for item in event.source().selectedItems():
print item.text(0)
def addItems(self, itemList):
"""
Take a list of path-like strings
"""
for item in itemList:
self.addItem(item)
def addItem(self, item):
"""
Convert each item to a tree item
"""
joints = item.strip('/').split('/')
joint = None
while joints:
joint = self.addTreeJoint(joints.pop(0), joint)
def addTreeJoint(self, jointName, parent=None):
"""
Add item to the tree widget
"""
returnItem = None
#If it the top of the tree
if not parent:
#Find existing item
for item in self.findItems(QtCore.QString(jointName),QtCore.Qt.MatchExactly):
if jointName == item.text(0):
return item
#Create new top level item
returnItem = MyTreeItem(self)
returnItem.setText(0, jointName)
#We search all the children of this tree level and figure out if
#we need to create a new tree item.
else:
for idx in range(parent.childCount()):
if parent.childCount() == 0:
break
if jointName == parent.child(idx).text(0):
return parent.child(idx)
#Create new item
returnItem = MyTreeItem(parent)
returnItem.setText(0, jointName)
return returnItem
class GeometrySelector(QtGui.QWidget):
accepted = QtCore.pyqtSignal(list)
def __init__(self, parent = None):
super(GeometrySelector, self).__init__(parent)
self.treeWidget = MyTreeWidget(self)
self.treeWidget.addItems(get_objs())
button = QtGui.QPushButton('Add Members', self)
button.setFocusPolicy(QtCore.Qt.NoFocus)
button.clicked.connect(self.cb_accept)
filterLabel = QtGui.QLabel(self)
filterLabel.setText('Filter:')
filterField = QtGui.QLineEdit(self)
filterField.textChanged.connect(self.filterChanged)
filterBox = QtGui.QHBoxLayout()
filterBox.addWidget(filterLabel)
filterBox.addWidget(filterField)
mainLayout = QtGui.QGridLayout()
mainLayout.addWidget(self.treeWidget,0,0)
mainLayout.addLayout(filterBox,1,0)
mainLayout.addWidget(button,2,0)
self.setLayout(mainLayout)
pal = self.palette()
pal.setColor(QtGui.QPalette.Base, QtGui.QColor(80, 80, 80))
pal.setColor(QtGui.QPalette.Text, QtGui.QColor(230, 230, 230))
self.setPalette(pal)
button.setPalette(pal)
self.treeWidget.setPalette(pal)
def filterChanged(self, filterStr):
showedItem = []
matchFlag = QtCore.Qt.MatchFlags(QtCore.Qt.MatchContains | QtCore.Qt.MatchRecursive | QtCore.Qt.MatchRegExp)
allItems = self.treeWidget.findItems(QtCore.QString("*"),matchFlag)
for item in allItems:
if item in showedItem:
continue
if str(filterStr) in str(item.text(0)):
showedItem.append(item)
showedItem.extend(item.getParents())
showedItem.extend(item.getChildren())
for item in allItems:
if item in showedItem:
item.setHidden(False)
else:
item.setHidden(True)
def cb_accept(self):
selected_things = [str(item.getPath()) for item in self.treeWidget.selectedItems()]
self.accepted.emit(selected_things)
class myWidget(QtGui.QWidget):
def __init__(self, parent = None):
super(myWidget, self).__init__(parent)
s1 = GeometrySelector(self)
s2 = GeometrySelector(self)
filterBox = QtGui.QHBoxLayout()
filterBox.addWidget(s1)
filterBox.addWidget(s2)
self.setLayout(filterBox)
def get_objs():
obj = ['/home/someone/something/somewhere','/home/someone/something/somewhere1','/home/someone/something/somewhere2',
'/home/someoneA/something/somewhere','/home/someoneA/somethingA/somewhere','/home/someoneA/somethingA/somewhere',
'/home/someoneC/something/somewhere','/home/someoneC/something/somewhereC','/home/someoneC/something/somewhereA']
return obj
def openUI():
app = QtGui.QApplication.instance()
if app is None:
app = QtGui.QApplication([])
dialog = myWidget()
dialog.show()
app.exec_()
openUI()
mouseReleaseEvent
andself.setAcceptDrops
in that method. – Radio-