可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Hey I had been going through this tutorial for understanding drag and drop methods in PyQt4. However I am not able to understand the following points . It would be nice if somepne could make it clearer to me.
def mouseMoveEvent(self, e): //class Button mimeData = QtCore.QMimeData() drag = QtGui.QDrag(self) drag.setMimeData(mimeData) drag.setHotSpot(e.pos() - self.rect().topLeft()) dropAction = drag.start(QtCore.Qt.MoveAction) def dropEvent(self, e): //class Example position = e.pos() self.button.move(position) e.setDropAction(QtCore.Qt.MoveAction) e.accept()
Why is there are a seperate self.button.move() and e.setDropAction() Doesnt self.button.move() actually move the button itself? And could someone explain what drag.setHotSpot and drag.start() do? Thanks.
回答1:
That tutorial is seriously outdated. QDrag.start is obsolete since Qt 4.3. QDrag.exec_ should be used instead.
As you can see from the docs for exec, it has a return value. setDropAction in dropEvent determines this value. It doesn't perform the move. That's why you need a self.button.move() to do the actual moving. So, what's the point of a setDropAction? You might need to know what kind of drag operation you did. Imagine you're implementing drag-drop between two list widgets. If you did a move operation, that means you need to remove the item from the source widget and create one in the target. If it was a copy operation, you can leave the original and just create a copy in the target.
setHotSpot/hotSpot is related to the setPixmap of a QDrag. You can display a QPixmap as you drag the item. hotSpot determines the positioning of the pixmap. The pixmap will be positioned such that the cursor will be at hotSpot relative to the top-left corner of the pixmap. So, in the case of that tutorial, it is rather pointless since there is no pixmap to be shown.
Here is a bit modified and updated version of that tutorial. Hopefully, I've included enough comments. You can move with Right-Click or copy with Shift + Right-Click:
#!/usr/bin/python # -*- coding: utf-8 -*- import sys from PyQt4 import QtGui, QtCore class Button(QtGui.QPushButton): def mouseMoveEvent(self, e): if e.buttons() != QtCore.Qt.RightButton: return # write the relative cursor position to mime data mimeData = QtCore.QMimeData() # simple string with 'x,y' mimeData.setText('%d,%d' % (e.x(), e.y())) # let's make it fancy. we'll show a "ghost" of the button as we drag # grab the button to a pixmap pixmap = QtGui.QPixmap.grabWidget(self) # below makes the pixmap half transparent painter = QtGui.QPainter(pixmap) painter.setCompositionMode(painter.CompositionMode_DestinationIn) painter.fillRect(pixmap.rect(), QtGui.QColor(0, 0, 0, 127)) painter.end() # make a QDrag drag = QtGui.QDrag(self) # put our MimeData drag.setMimeData(mimeData) # set its Pixmap drag.setPixmap(pixmap) # shift the Pixmap so that it coincides with the cursor position drag.setHotSpot(e.pos()) # start the drag operation # exec_ will return the accepted action from dropEvent if drag.exec_(QtCore.Qt.CopyAction | QtCore.Qt.MoveAction) == QtCore.Qt.MoveAction: print 'moved' else: print 'copied' def mousePressEvent(self, e): QtGui.QPushButton.mousePressEvent(self, e) if e.button() == QtCore.Qt.LeftButton: print 'press' class Example(QtGui.QWidget): def __init__(self): super(Example, self).__init__() self.initUI() def initUI(self): self.setAcceptDrops(True) button = Button('Button', self) button.move(100, 65) self.buttons = [button] self.setWindowTitle('Copy or Move') self.setGeometry(300, 300, 280, 150) def dragEnterEvent(self, e): e.accept() def dropEvent(self, e): # get the relative position from the mime data mime = e.mimeData().text() x, y = map(int, mime.split(',')) if e.keyboardModifiers() & QtCore.Qt.ShiftModifier: # copy # so create a new button button = Button('Button', self) # move it to the position adjusted with the cursor position at drag button.move(e.pos()-QtCore.QPoint(x, y)) # show it button.show() # store it self.buttons.append(button) # set the drop action as Copy e.setDropAction(QtCore.Qt.CopyAction) else: # move # so move the dragged button (i.e. event.source()) e.source().move(e.pos()-QtCore.QPoint(x, y)) # set the drop action as Move e.setDropAction(QtCore.Qt.MoveAction) # tell the QDrag we accepted it e.accept() if __name__ == '__main__': app = QtGui.QApplication(sys.argv) ex = Example() ex.show() app.exec_()
回答2:
Avaris' answer adapted for PyQt5 and Python 3.
#!/usr/bin/python # -*- coding: utf-8 -*- # Adapted for PyQt5 and Python 3 from Avaris' answer to # https://stackoverflow.com/questions/14395799/pyqt4-drag-and-drop import sys from PyQt5.QtWidgets import QPushButton, QWidget, QApplication from PyQt5.QtCore import Qt, QMimeData, QPoint from PyQt5.QtGui import QDrag, QPixmap, QPainter, QColor class Button(QPushButton): def mouseMoveEvent(self, e): if e.buttons() != Qt.RightButton: return # write the relative cursor position to mime data mimeData = QMimeData() # simple string with 'x,y' mimeData.setText('%d,%d' % (e.x(), e.y())) # let's make it fancy. we'll show a "ghost" of the button as we drag # grab the button to a pixmap pixmap = QWidget.grab(self) # below makes the pixmap half transparent painter = QPainter(pixmap) painter.setCompositionMode(painter.CompositionMode_DestinationIn) painter.fillRect(pixmap.rect(), QColor(0, 0, 0, 127)) painter.end() # make a QDrag drag = QDrag(self) # put our MimeData drag.setMimeData(mimeData) # set its Pixmap drag.setPixmap(pixmap) # shift the Pixmap so that it coincides with the cursor position drag.setHotSpot(e.pos()) # start the drag operation # exec_ will return the accepted action from dropEvent if drag.exec_(Qt.CopyAction | Qt.MoveAction) == Qt.MoveAction: print('moved') else: print('copied') def mousePressEvent(self, e): QPushButton.mousePressEvent(self, e) if e.button() == Qt.LeftButton: print('press') class Example(QWidget): def __init__(self): super(Example, self).__init__() self.initUI() def initUI(self): self.setAcceptDrops(True) button = Button('Button', self) button.move(100, 65) self.buttons = [button] self.setWindowTitle('Copy or Move') self.setGeometry(300, 300, 280, 150) def dragEnterEvent(self, e): e.accept() def dropEvent(self, e): # get the relative position from the mime data mime = e.mimeData().text() x, y = map(int, mime.split(',')) if e.keyboardModifiers() & Qt.ShiftModifier: # copy # so create a new button button = Button('Button', self) # move it to the position adjusted with the cursor position at drag button.move(e.pos()-QPoint(x, y)) # show it button.show() # store it self.buttons.append(button) # set the drop action as Copy e.setDropAction(Qt.CopyAction) else: # move # so move the dragged button (i.e. event.source()) e.source().move(e.pos()-QPoint(x, y)) # set the drop action as Move e.setDropAction(Qt.MoveAction) # tell the QDrag we accepted it e.accept() if __name__ == '__main__': app = QApplication(sys.argv) ex = Example() ex.show() app.exec_()