Python qt: copy/paste and drag/drop
MimeData
Links list of formally accepted mimetypes http://www.iana.org/assignments/media-types/media-types.xhtml Mimetype Naming Conventions officially recognized mimetypes application/json
non-official mimetypes x-
prefixapplication/x-yaml
platform-specific mimetypes See QMimedata application/x-qt-windows-mime;value="<custom type>"
mimetypes describe the type of data a file contains. On unix-based platforms, these mimetypes can be associated with programs that should be used to open them.
This information is also used when pasting items from the clipboard. During a paste operation, your clipboard's content's mimetype in the active window. If you program knows how to handle this mimetype, the paste is accepted, and it is pasted into the program. Otherwise it is silently rejected.
QtCore.QMimeData
is Qt's object for storing mimetype-aware data. To maximize the number of programs that can handle your data, you may want to express the same data in a few different formats (ex: 'text/plain', 'application/json', 'application/yaml', ...etc...).from Qt import QtCore data = {'name': 'will', 'age': 32} qmimedata = QtCore.QMimeData() qmimedata.setData('text/plain', data['name']) qmimedata.setData('application/json', json.dumps(data)) qmimedata.setData('application/yaml', yaml.dumps(data))
For more information, see mimetypes .
Copy/Paste
example widget implementing both copy/paste
from Qt import QtWidgets, QtCore, QtGui class CopyPasteWidget(QtWidgets.QLabel): def __init__(self): super(CopyPasteWidget, self).__init__( 'Try Ctrl+C/Ctrl+V on this widget.<br>' 'Copied data can also be pasted into other programs, and vice-versa' ) self._create_actions() def _create_actions(self): # create actions self.copy_action = QtWidgets.QAction('Copy', parent=self) self.paste_action = QtWidgets.QAction('Paste', parent=self) # add actions to widget (widget watches for keysequence) self.addAction(self.copy_action) self.addAction(self.paste_action) # set shortcuts # NOTE (QKeySequence.StandardKey entries are platform-specific. confirm they are bound!) self.copy_action.setShortcut(QtGui.QKeySequence.Copy) self.paste_action.setShortcut(QtGui.QKeySequence.Paste) # connections self.copy_action.triggered.connect(self._handle_copy) self.paste_action.triggered.connect(self._handle_paste) def _handle_copy(self, *args, **kwargs): qmimedata = QtCore.QMimeData() clipboard = QtWidgets.QApplication.clipboard() copy_data = 'plaintext data'.encode('utf-8') # your data, as a bytestr qmimedata.setData('text/plain', QtCore.QByteArray(copy_data)) clipboard.clear() clipboard.setMimeData(qmimedata) print('copied data: "{}"'.format(copy_data)) def _handle_paste(self, *args, **kwargs): clipboard = QtWidgets.QApplication.clipboard() qmimedata = clipboard.mimeData() if qmimedata.hasFormat('text/plain'): copy_data = qmimedata.data('text/plain') print('pasted data: "{}"'.format(copy_data)) else: print('paste ignored')NOTE:
mimetypes on windows/osx do not always match exactly with the open standards.See QWinMime and QMacPasteboardMime for conversions to/from the open mimetype standards.
Drag/Drop (widgets)
Dragging and Dropping Widgets require:
- A Customized Drop Widget Class
- A Customized Drag Widget Class
Note that you can always access the dropped object from the object receiving it with
event.source()
. Drop Events cannot be made on layouts, but they CAN be made on QWidgets containing layouts and several other widgets.Drag Widget
class DragButton(QtGui.QPushButton): def __init__(self, *args, **kwds ): super(DragButton, self).__init__(*args, **kwds) def mouseMoveEvent(self, event): """ MimeData allows you to create custom mimetypes to be used to validate the dataType on the other end. These can be nonsense to ensure that you are actually getting the info you want. Or, if it is simply text, images, or some other objectType you want to be reusable, across different windows, you can make them all use consistent mimetypes. """ if event.buttons() != QtCore.Qt.LeftButton: return mimeData = QtCore.QMimeData() mimeData.setData('application/x-interpipeline', 'neato') drag = QtGui.QDrag(self) drag.setMimeData(mimeData) drag.exec_()Drop Widget
class DropTextEdit( QtGui.QTextEdit ): def __init__( self, *args, **kwds ): super( DropTextEdit, self ).__init__( *args, **kwds ) self.setAcceptDrops(1) ## Make sure to actually accept drops def dragEnterEvent( self, event ): """ ''Drop Event Stage 1'' Run When an object is dragged into the widget (with mouse button still being held) This Method determines if the dropEvent should be accepted or not. """ print event.mimeData().formats() ## List of All possible Mimetypes attached to data if event.mimeData().hasFormat('application/x-interpipeline'): event.accept() def dragMoveEvent( self, event ): """ ''Drop Event Stage 2'' Run When an object is moved within the widget (with mouse button still being held) IMPORTANT: Without this method, dropEvent is not called. (weird, right?) """ pass def dropEvent(self, event): """ ''Drop Event Stage 3'' Run if mouse is released over widget, and event.accept() is set in dragEnterEvent(). """ print event.source() ## The object being dragged if event.mimeData().hasFormat('application/x-interpipeline'): data = event.mimeData().data('application/x-interpipeline') print data
Drag/Drop (views)
https://doc.qt.io/archives/4.6/model-view-dnd.html
https://doc.qt.io/qt-5/model-view-programming.html#using-drag-and-drop-with-item-views