Reputation: 7879
This python pyqt code works how I intended. But, I don't like having to subclass QLineEdit so that I can detect file drop onto my QLineEdit field. I like the more elegant and simpler "connect" technique (new style signal/slot handling) that I used to detect text changes to the edit field.
My question: Is there a signal/slot connect solution for handling drops on the edit field without having to subclass QLineEdit?
Also, it is annoying that I must implement both methods in the subclass... dragEnterEvent & dropEvent to make the drop work!
import sys
from PyQt4 import QtGui, QtCore
class dropedit(QtGui.QLineEdit): # subclass
def __init__(self, parent=None):
super(dropedit, self).__init__(parent)
self.setDragEnabled(True)
self.setAcceptDrops(True)
def dragEnterEvent(self, event):
print "dragEnterEvent:"
if event.mimeData().hasUrls():
event.accept() # must accept the dragEnterEvent or else the dropEvent can't occur !!!
else:
event.ignore()
def dropEvent(self, event):
if event.mimeData().hasUrls(): # if file or link is dropped
urlcount = len(event.mimeData().urls()) # count number of drops
url = event.mimeData().urls()[0] # get first url
self.setText(url.toString()) # assign first url to editline
#event.accept() # doesnt appear to be needed
class testDialog(QtGui.QDialog):
def __init__(self, parent=None):
super(testDialog, self).__init__(parent)
form = QtGui.QFormLayout()
form.setHorizontalSpacing(0)
myedit = dropedit()
form.addWidget(myedit)
self.setLayout(form)
self.setGeometry(300, 300, 400, 0)
self.setWindowTitle('drop test')
myedit.textChanged.connect(self.editchange) # new style signal slot connections
@QtCore.pyqtSlot(str) # int represent the column value
def editchange(self,data):
print "editchange:", data
if __name__ == "__main__":
app = QtGui.QApplication([])
dl = testDialog()
dl.exec_()
sys.exit(app.closeAllWindows())
Upvotes: 1
Views: 5034
Reputation: 11
I had the same issue today and has able to get it solved in a different (and maybe less orthodoxy) way. So, what can also be done is to remap the dropEvent function from the tree to another name, either internal to the instance or to the class that owns the instance, and assign a new custom function the dropEvent. This new function can call or not the original one, depending if you want to keep some of the functionallities, or just rewrite everything. Here is a snippet:
import sys
from PyQt5.QtWidgets import QTreeView
from PyQt5.QtGui import QDropEvent
class Demo:
def __init__(self):
self.tree = QTreeView()
self.tree.setDragEnabled(True)
self.tree.setAcceptDrops(True)
self.tree.original_dropEvent = self.dataView.dropEvent
self.tree.dropEvent = self._dataview_dropevent
def _tree_dropevent(self, event: QDropEvent):
# do stuff ...
self.tree.original_dropEvent(event)
# maybe more stuff ..
.
Upvotes: 0
Reputation: 3775
No need to subclass: you can use an event filter:
import sys
from PyQt4 import QtGui, QtCore
class testDialog(QtGui.QDialog):
def __init__(self, parent=None):
super(testDialog, self).__init__(parent)
form = QtGui.QFormLayout()
form.setHorizontalSpacing(0)
self.myedit = QtGui.QLineEdit()
self.myedit.setDragEnabled(True)
self.myedit.setAcceptDrops(True)
self.myedit.installEventFilter(self)
form.addWidget(self.myedit)
self.setLayout(form)
self.setGeometry(300, 300, 400, 0)
self.setWindowTitle('drop test')
self.myedit.textChanged.connect(self.editchange) # new style signal slot connections
@QtCore.pyqtSlot(str) # int represent the column value
def editchange(self,data):
print "editchange:", data.toLatin1()
def eventFilter(self, object, event):
if (object is self.myedit):
if (event.type() == QtCore.QEvent.DragEnter):
if event.mimeData().hasUrls():
event.accept() # must accept the dragEnterEvent or else the dropEvent can't occur !!!
print "accept"
else:
event.ignore()
print "ignore"
if (event.type() == QtCore.QEvent.Drop):
if event.mimeData().hasUrls(): # if file or link is dropped
urlcount = len(event.mimeData().urls()) # count number of drops
url = event.mimeData().urls()[0] # get first url
object.setText(url.toString()) # assign first url to editline
#event.accept() # doesnt appear to be needed
return False # lets the event continue to the edit
return False
if __name__ == "__main__":
app = QtGui.QApplication([])
dl = testDialog()
dl.exec_()
sys.exit(app.closeAllWindows())
Upvotes: 3