2013-01-18 21 views
8

अरे मैं PyQt4 में ड्रैग और ड्रॉप विधियों को समझने के लिए इस tutorial के माध्यम से जा रहा था। हालांकि मैं निम्नलिखित बिंदुओं को समझने में सक्षम नहीं हूं। यह अच्छा होगा अगर कुछ लोग मुझे स्पष्ट कर सकें।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() Does not को self.button.move() वास्तव में बटन ही ले जाते हैं देखते हैं क्या है? और क्या कोई यह बता सकता है कि drag.setHotSpot और drag.start() क्या करते हैं? धन्यवाद।

उत्तर

15

वह ट्यूटोरियल गंभीर रूप से पुराना है। Qt 4.3 से अप्रचलित है। इसके बजाय QDrag.exec_ का उपयोग किया जाना चाहिए।

जैसा कि आप exec के लिए दस्तावेज़ों से देख सकते हैं, इसके पास वापसी मूल्य है। setDropActiondropEvent में यह मान निर्धारित करता है। यह कदम नहीं करता है। यही कारण है कि वास्तविक चलने के लिए आपको self.button.move() की आवश्यकता है। तो, setDropAction का बिंदु क्या है? आपको यह जानने की आवश्यकता हो सकती है कि आपने किस तरह का ड्रैग ऑपरेशन किया था। कल्पना करें कि आप दो सूची विजेट्स के बीच ड्रैग-ड्रॉप लागू कर रहे हैं। यदि आपने एक चाल ऑपरेशन किया है, तो इसका मतलब है कि आपको स्रोत विजेट से आइटम को निकालने और लक्ष्य में एक बनाने की आवश्यकता है। अगर यह एक प्रतिलिपि ऑपरेशन था, तो आप मूल छोड़ सकते हैं और केवल लक्ष्य में एक प्रति बना सकते हैं।

setHotSpot/hotSpotQDrag के setPixmap से संबंधित है। जब आप आइटम खींचते हैं तो आप QPixmap प्रदर्शित कर सकते हैं। hotSpot पिक्समैप की स्थिति निर्धारित करता है। पिक्समैप को इस प्रकार रखा जाएगा कि कर्सर hotSpot पर पिक्समैप के ऊपरी-बाएं कोने के सापेक्ष होगा। तो, उस ट्यूटोरियल के मामले में, यह दिखाए जाने के लिए कोई पिक्समैप नहीं है क्योंकि यह व्यर्थ है।

यहां ट्यूटोरियल का थोड़ा संशोधित और अद्यतन संस्करण है। उम्मीद है कि, मैंने पर्याप्त टिप्पणियां शामिल की हैं। आप Right-Click या प्रतिलिपि साथ स्थानांतरित कर सकते हैं 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_() 
+0

अद्भुत जवाब के लिए धन्यवाद के लिए अनुकूलित। हालांकि मुझे अभी भी संदेह है, मैं बटन को e.pos() - QtCore.QPoint (x, y) पर क्यों ले जाता हूं। E.pos() स्वयं नहीं है, यह स्थिति कहां छोड़ दी जानी चाहिए? । और mimeData कर्सर की स्थिति नहीं देता है क्योंकि आपने इसे पूर्व() और ey() पर सेट किया है, जहां ई माउस की स्थिति है, और जब मैं इसे छोड़ देता हूं, तो e.pos() और QtCore.QPoint दोनों नहीं होंगे (एक्स, वाई)। मेरे नोबनेस के लिए खेद है। – Manoj

+1

@Manoj: 'mime' से आने वाला 'x' और' y' बटन के संबंध में कर्सर के _local position_ हैं। 'e.pos()' विजेट पर कर्सर की वास्तविक स्थिति होगी ('उदाहरण')। यदि आप बटन को 'e.pos()' पर ले जाना चाहते थे, तो यह उस स्थिति के बटन के ऊपरी-बाएं स्थानांतरित हो जाएगा। उदाहरण के लिए, आपने बटन के बीच में बटन उठाया। और यदि आप केवल 'e.pos()' के साथ नई कर्सर स्थिति में जाते हैं, तो बटन को आपके द्वारा उठाए गए तरीके से नहीं रखा जाएगा, बल्कि स्थानांतरित किया जाएगा। 'x, y' सही है कि बटन के ऊपरी-बाएं को समायोजित करके शिफ्ट करें कि कर्सर ड्रॉप के बाद एक ही स्थिति में होगा। – Avaris

+1

@Manoj: मुझे लगता है कि आपका भ्रम कोड में 'e.x()/e.y()' बनाम 'e.pos()' से आता है। जिस हिस्से को मैं 'e.x()/e.y()' प्राप्त करता हूं वह 'बटन' का 'माउसमोवइवेंट' है। तो वे बटन के सापेक्ष हैं ('0,0' शीर्ष बाएं होने के नाते)। 'उदाहरण' के 'ड्रॉपएवेंट' में' e.pos() 'कहां से। यह स्थिति 'उदाहरण' के संबंध में कर्सर की सापेक्ष स्थिति होगी। – Avaris

1

अवारिस 'जवाब PyQt5 और अजगर 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_() 
संबंधित मुद्दे