2013-01-18 15 views
8

ちょっと、私はPyQt4のドラッグアンドドロップ方法を理解するためにこのtutorialを調べていました。しかし、私は以下の点を理解することができません。 somepneが私にそれをより明確にすることができればそれはいいだろう。PyQt4 - ドラッグアンドドロップ

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() 

はなぜ別々self.button.move()とe.setDropAction()doesntのをself.button.move()実際にボタン自体を移動があるのですか?誰かがdrag.setHotSpotとdrag.start()が何をしているのか説明できますか?ありがとう。

答えて

15

このチュートリアルは真剣に時代遅れです。 QDrag.startQt 4.3以降廃止されました。代わりにQDrag.exec_を使用してください。

execのドキュメントからわかるように、戻り値があります。 setDropActiondropEventに設定すると、この値が決まります。それは移動を実行しません。そのため、実際に移動するにはself.button.move()が必要です。だから、setDropActionのポイントは何ですか?あなたがしたドラッグ操作の種類を知る必要があるかもしれません。 2つのリストウィジェット間でドラッグドロップを実装しているとします。移動操作を行った場合は、ソースウィジェットから項目を削除し、ターゲットに項目を作成する必要があることを意味します。コピー操作の場合は、元のままにして、ターゲットにコピーを作成するだけです。

setHotSpot/は、QDragsetPixmapに関連しています。項目をドラッグすると、QPixmapを表示することができます。 hotSpotは、ピクスマップの位置を決定します。 pixmapは、カーソルがpixmapの左上隅を基準にしてhotSpotになるように配置されます。したがって、このチュートリアルの場合は、表示するピクスマップがないので、無意味です。

ここでは、このチュートリアルの少し修正され、更新されたバージョンです。うまくいけば、私は十分なコメントを入れました。あなたはShift + Right-ClickRight-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_() 
+0

するようになっAvaris'答え素晴らしい答えをありがとう。しかし、私はまだ疑問があります。なぜボタンをe.pos() - QtCore.QPoint(x、y)に移動するのですか? e.pos()自身ではなく、落とすべき位置を指定しますか? 。そして、あなたがex()とey()にeを設定すると、マウスの位置がeであるので、e.pos()とQtCore.QPointの両方ではないので、mimeDataはカーソルの位置を与えません(x、y)である。申し訳ありませんが、私のnoobness。 – Manoj

+1

@Manoj: 'mime'から来る' x'と 'y'は、ボタンのカーソルの_local position_です。 'e.pos()'はウィジェット上のカーソルの実際の位置になります( 'Example')。ボタンを 'e.pos()'に移動すると、ボタンの左上がその位置に移動します。たとえば、ボタンの中央にあるボタンを選択したとします。そして、 'e.pos()'だけで新しいカーソル位置に移動すると、ボタンはあなたがピックアップした方法ではなく配置されます。 'x、y'は、カーソルがドロップ後も同じ位置にくるように、ボタンの左上を調整することによってシフトを修正します。 – Avaris

+1

@Manoj:あなたの混乱はコード内の 'e.x()/ e.y()' vs 'e.pos()'から来ていると思います。 'e.x()/ e.y()'を得る部分は 'Button'の' mouseMoveEvent'です。したがって、ボタンに相対的です(左上の「0,0」)。 'Example'の' dropEvent'に 'e.pos()'としています。それが与える位置は、 'Example'に対するカーソルの相対位置になります。 – Avaris

1

PyQt5と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_()