diff options
Diffstat (limited to 'examples/widgets/draganddrop')
15 files changed, 361 insertions, 47 deletions
diff --git a/examples/widgets/draganddrop/draggableicons/doc/draggableicons.png b/examples/widgets/draganddrop/draggableicons/doc/draggableicons.png Binary files differnew file mode 100644 index 000000000..640a99e44 --- /dev/null +++ b/examples/widgets/draganddrop/draggableicons/doc/draggableicons.png diff --git a/examples/widgets/draganddrop/draggableicons/doc/draggableicons.rst b/examples/widgets/draganddrop/draggableicons/doc/draggableicons.rst new file mode 100644 index 000000000..3f67e5809 --- /dev/null +++ b/examples/widgets/draganddrop/draggableicons/doc/draggableicons.rst @@ -0,0 +1,9 @@ +Draggable Icons Example +======================= + +The Draggable Icons example shows how to drag and drop image data between +widgets in the same application,and between different applications. + +.. image:: draggableicons.png + :width: 536 + :alt: draggable icons screenshot diff --git a/examples/widgets/draganddrop/draggableicons/draggableicons.py b/examples/widgets/draganddrop/draggableicons/draggableicons.py new file mode 100644 index 000000000..b929bd5e3 --- /dev/null +++ b/examples/widgets/draganddrop/draggableicons/draggableicons.py @@ -0,0 +1,128 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +from pathlib import Path +import sys + +from PySide6.QtCore import QByteArray, QDataStream, QIODevice, QMimeData, QPoint, Qt +from PySide6.QtGui import QColor, QDrag, QPainter, QPixmap +from PySide6.QtWidgets import QApplication, QFrame, QHBoxLayout, QLabel, QWidget + + +class DragWidget(QFrame): + def __init__(self, parent: QWidget): + super().__init__(parent) + self.setMinimumSize(200, 200) + self.setFrameStyle(QFrame.Sunken | QFrame.StyledPanel) + self.setAcceptDrops(True) + + path = Path(__file__).resolve().parent + + boat_icon = QLabel(self) + boat_icon.setPixmap(QPixmap(path / "images" / "boat.png")) + boat_icon.move(10, 10) + boat_icon.show() + boat_icon.setAttribute(Qt.WA_DeleteOnClose) + + car_icon = QLabel(self) + car_icon.setPixmap(QPixmap(path / "images" / "car.png")) + car_icon.move(100, 10) + car_icon.show() + car_icon.setAttribute(Qt.WA_DeleteOnClose) + + house_icon = QLabel(self) + house_icon.setPixmap(QPixmap(path / "images" / "house.png")) + house_icon.move(10, 80) + house_icon.show() + house_icon.setAttribute(Qt.WA_DeleteOnClose) + + def dragEnterEvent(self, event): + if event.mimeData().hasFormat("application/x-dnditem_data"): + if event.source() == self: + event.setDropAction(Qt.MoveAction) + event.accept() + else: + event.acceptProposedAction() + else: + event.ignore() + + def dragMoveEvent(self, event): + if event.mimeData().hasFormat("application/x-dnditem_data"): + if event.source() == self: + event.setDropAction(Qt.MoveAction) + event.accept() + else: + event.acceptProposedAction() + else: + event.ignore() + + def dropEvent(self, event): + if event.mimeData().hasFormat("application/x-dnditem_data"): + item_data: QByteArray = event.mimeData().data("application/x-dnditem_data") + data_stream = QDataStream(item_data, QIODevice.ReadOnly) + + pixmap = QPixmap() + offset = QPoint() + + data_stream >> pixmap >> offset + + new_icon = QLabel(self) + new_icon.setPixmap(pixmap) + new_icon.move(event.position().toPoint() - offset) + new_icon.show() + new_icon.setAttribute(Qt.WA_DeleteOnClose) + + if event.source() == self: + event.setDropAction(Qt.MoveAction) + event.accept() + else: + event.acceptProposedAction() + else: + event.ignore() + + def mousePressEvent(self, event): + child: QLabel = self.childAt(event.position().toPoint()) + if not child: + return + + pixmap = child.pixmap() + + item_data = QByteArray() + data_stream = QDataStream(item_data, QIODevice.WriteOnly) + + data_stream << pixmap << QPoint(event.position().toPoint() - child.pos()) + + mime_data = QMimeData() + mime_data.setData("application/x-dnditem_data", item_data) + + drag = QDrag(self) + drag.setMimeData(mime_data) + drag.setPixmap(pixmap) + drag.setHotSpot(event.position().toPoint() - child.pos()) + + # .copy() is important: python is different than c++ in this case + temp_pixmap = pixmap.copy() + with QPainter(temp_pixmap) as painter: + painter.fillRect(pixmap.rect(), QColor(127, 127, 127, 127)) + + child.setPixmap(temp_pixmap) + + if drag.exec(Qt.CopyAction | Qt.MoveAction, Qt.CopyAction) == Qt.MoveAction: + child.close() + else: + child.show() + child.setPixmap(pixmap) + + +if __name__ == "__main__": + app = QApplication(sys.argv) + + main_widget = QWidget() + horizontal_layout = QHBoxLayout(main_widget) + horizontal_layout.addWidget(DragWidget(main_widget)) + horizontal_layout.addWidget(DragWidget(main_widget)) + + main_widget.setWindowTitle("Draggable Icons") + main_widget.show() + + sys.exit(app.exec()) diff --git a/examples/widgets/draganddrop/draggableicons/draggableicons.qrc b/examples/widgets/draganddrop/draggableicons/draggableicons.qrc new file mode 100644 index 000000000..63f84ac06 --- /dev/null +++ b/examples/widgets/draganddrop/draggableicons/draggableicons.qrc @@ -0,0 +1,7 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource prefix=""> + <file>images/boat.png</file> + <file>images/car.png</file> + <file>images/house.png</file> +</qresource> +</RCC> diff --git a/examples/widgets/draganddrop/draggableicons/images/boat.png b/examples/widgets/draganddrop/draggableicons/images/boat.png Binary files differnew file mode 100644 index 000000000..46c894f06 --- /dev/null +++ b/examples/widgets/draganddrop/draggableicons/images/boat.png diff --git a/examples/widgets/draganddrop/draggableicons/images/car.png b/examples/widgets/draganddrop/draggableicons/images/car.png Binary files differnew file mode 100644 index 000000000..3cb35e56c --- /dev/null +++ b/examples/widgets/draganddrop/draggableicons/images/car.png diff --git a/examples/widgets/draganddrop/draggableicons/images/house.png b/examples/widgets/draganddrop/draggableicons/images/house.png Binary files differnew file mode 100644 index 000000000..ee9d5b115 --- /dev/null +++ b/examples/widgets/draganddrop/draggableicons/images/house.png diff --git a/examples/widgets/draganddrop/draggabletext/draggabletext.py b/examples/widgets/draganddrop/draggabletext/draggabletext.py index 9595b0d2c..6ffdbd70e 100644 --- a/examples/widgets/draganddrop/draggabletext/draggabletext.py +++ b/examples/widgets/draganddrop/draggabletext/draggabletext.py @@ -1,52 +1,15 @@ +# Copyright (C) 2013 Riverbank Computing Limited. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause -############################################################################# -## -## Copyright (C) 2013 Riverbank Computing Limited. -## Copyright (C) 2016 The Qt Company Ltd. -## Contact: http://www.qt.io/licensing/ -## -## This file is part of the Qt for Python examples of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:BSD$ -## You may use this file under the terms of the BSD license as follows: -## -## "Redistribution and use in source and binary forms, with or without -## modification, are permitted provided that the following conditions are -## met: -## * Redistributions of source code must retain the above copyright -## notice, this list of conditions and the following disclaimer. -## * Redistributions in binary form must reproduce the above copyright -## notice, this list of conditions and the following disclaimer in -## the documentation and/or other materials provided with the -## distribution. -## * Neither the name of The Qt Company Ltd nor the names of its -## contributors may be used to endorse or promote products derived -## from this software without specific prior written permission. -## -## -## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -## -## $QT_END_LICENSE$ -## -############################################################################# - -"""PySide6 port of the widgets/draganddrop/draggabletext example from Qt v5.x, originating from PyQt""" +"""PySide6 port of the widgets/draganddrop/draggabletext example from Qt v5.x, + originating from PyQt""" from PySide6.QtCore import QFile, QIODevice, QMimeData, QPoint, Qt, QTextStream from PySide6.QtGui import QDrag, QPalette, QPixmap from PySide6.QtWidgets import QApplication, QFrame, QLabel, QWidget -import draggabletext_rc +import draggabletext_rc # noqa: F401 class DragLabel(QLabel): diff --git a/examples/widgets/draganddrop/draggabletext/draggabletext.pyproject b/examples/widgets/draganddrop/draggabletext/draggabletext.pyproject index 0d422076e..fd97c9096 100644 --- a/examples/widgets/draganddrop/draggabletext/draggabletext.pyproject +++ b/examples/widgets/draganddrop/draggabletext/draggabletext.pyproject @@ -1,4 +1,3 @@ { - "files": ["draggabletext_rc.py", "words.txt", "draggabletext.qrc", - "draggabletext.py"] + "files": ["words.txt", "draggabletext.qrc", "draggabletext.py"] } diff --git a/examples/widgets/draganddrop/draggabletext/draggabletext_rc.py b/examples/widgets/draganddrop/draggabletext/draggabletext_rc.py index e1d19bd91..30c01ce64 100644 --- a/examples/widgets/draganddrop/draggabletext/draggabletext_rc.py +++ b/examples/widgets/draganddrop/draggabletext/draggabletext_rc.py @@ -1,6 +1,6 @@ # Resource object code (Python 3) # Created by: object code -# Created by: The Resource Compiler for Qt version 5.14.0 +# Created by: The Resource Compiler for Qt version 6.2.2 # WARNING! All changes made in this file will be lost! from PySide6 import QtCore @@ -43,7 +43,7 @@ qt_resource_struct = b"\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x00\x1a\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ -\x00\x00\x01e\xaf\x16\xd2\x9d\ +\x00\x00\x01z\xe7\xee'\x05\ " def qInitResources(): diff --git a/examples/widgets/draganddrop/dropsite/doc/dropsite.rst b/examples/widgets/draganddrop/dropsite/doc/dropsite.rst new file mode 100644 index 000000000..8d6c42bc8 --- /dev/null +++ b/examples/widgets/draganddrop/dropsite/doc/dropsite.rst @@ -0,0 +1,8 @@ +Drop Site Example +================= + +The Drop Site example shows how to distinguish the various MIME formats +available in a drag and drop operation. + +It accepts drops from other applications and displays the MIME formats +provided by the drag object. diff --git a/examples/widgets/draganddrop/dropsite/droparea.py b/examples/widgets/draganddrop/dropsite/droparea.py new file mode 100644 index 000000000..efc4614f0 --- /dev/null +++ b/examples/widgets/draganddrop/dropsite/droparea.py @@ -0,0 +1,67 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +from PySide6.QtCore import QMimeData, Qt, Slot, Signal +from PySide6.QtGui import QPalette, QPixmap +from PySide6.QtWidgets import QFrame, QLabel + + +class DropArea(QLabel): + + changed = Signal(QMimeData) + + def __init__(self, parent=None): + super().__init__(parent) + self.setMinimumSize(200, 200) + self.setFrameStyle(QFrame.Sunken | QFrame.StyledPanel) + self.setAlignment(Qt.AlignCenter) + self.setAcceptDrops(True) + self.setAutoFillBackground(True) + self.clear() + + def dragEnterEvent(self, event): + self.setText("<drop content>") + self.setBackgroundRole(QPalette.Highlight) + + event.acceptProposedAction() + self.changed.emit(event.mimeData()) + + def dragMoveEvent(self, event): + event.acceptProposedAction() + + def dropEvent(self, event): + mime_data = event.mimeData() + + if mime_data.hasImage(): + self.setPixmap(QPixmap(mime_data.imageData())) + elif mime_data.hasFormat("text/markdown"): + self.setText(mime_data.data("text/markdown")) + self.setTextFormat(Qt.MarkdownText) + elif mime_data.hasHtml(): + self.setText(mime_data.html()) + self.setTextFormat(Qt.RichText) + elif mime_data.hasText(): + self.setText(mime_data.text()) + self.setTextFormat(Qt.PlainText) + elif mime_data.hasUrls(): + url_list = mime_data.urls() + text = "" + for i in range(0, min(len(url_list), 32)): + text += url_list[i].path() + "\n" + self.setText(text) + else: + self.setText("Cannot display data") + + self.setBackgroundRole(QPalette.Dark) + event.acceptProposedAction() + + def dragLeaveEvent(self, event): + self.clear() + event.accept() + + @Slot() + def clear(self): + self.setText("<drop content>") + self.setBackgroundRole(QPalette.Dark) + + self.changed.emit(None) diff --git a/examples/widgets/draganddrop/dropsite/dropsite.pyproject b/examples/widgets/draganddrop/dropsite/dropsite.pyproject new file mode 100644 index 000000000..0173d5cb9 --- /dev/null +++ b/examples/widgets/draganddrop/dropsite/dropsite.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["main.py", "droparea.py", "dropsitewindow.py"] +} diff --git a/examples/widgets/draganddrop/dropsite/dropsitewindow.py b/examples/widgets/draganddrop/dropsite/dropsitewindow.py new file mode 100644 index 000000000..5427d520d --- /dev/null +++ b/examples/widgets/draganddrop/dropsite/dropsitewindow.py @@ -0,0 +1,115 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import re +from PySide6.QtCore import QMimeData, Qt, Slot +from PySide6.QtGui import QGuiApplication +from PySide6.QtWidgets import (QAbstractItemView, QPushButton, + QDialogButtonBox, QLabel, + QTableWidget, QTableWidgetItem, + QVBoxLayout, QWidget) + +from droparea import DropArea + +DESCRIPTION = """This example accepts drags from other applications and +displays the MIME types provided by the drag object.""" + + +_WHITESPACE_PATTERN = re.compile(r"\s+") + + +def simplify_whitespace(s): + return _WHITESPACE_PATTERN.sub(" ", s).strip() + + +class DropSiteWindow(QWidget): + + def __init__(self): + super().__init__() + drop_area = DropArea() + abstract_label = QLabel() + self._formats_table = QTableWidget() + + button_box = QDialogButtonBox() + abstract_label = QLabel(DESCRIPTION) + abstract_label.setWordWrap(True) + abstract_label.adjustSize() + + drop_area = DropArea() + drop_area.changed.connect(self.update_formats_table) + + self._formats_table = QTableWidget() + self._formats_table.setColumnCount(2) + self._formats_table.setEditTriggers(QAbstractItemView.NoEditTriggers) + self._formats_table.setHorizontalHeaderLabels(["Format", "Content"]) + self._formats_table.horizontalHeader().setStretchLastSection(True) + + clear_button = QPushButton("Clear") + self._copy_button = QPushButton("Copy") + quit_button = QPushButton("Quit") + + button_box = QDialogButtonBox() + button_box.addButton(clear_button, QDialogButtonBox.ActionRole) + button_box.addButton(self._copy_button, QDialogButtonBox.ActionRole) + self._copy_button.setVisible(False) + + button_box.addButton(quit_button, QDialogButtonBox.RejectRole) + + quit_button.clicked.connect(self.close) + clear_button.clicked.connect(drop_area.clear) + self._copy_button.clicked.connect(self.copy) + + main_layout = QVBoxLayout(self) + main_layout.addWidget(abstract_label) + main_layout.addWidget(drop_area) + main_layout.addWidget(self._formats_table) + main_layout.addWidget(button_box) + + self.setWindowTitle("Drop Site") + self.resize(700, 500) + + @Slot(QMimeData) + def update_formats_table(self, mime_data): + self._formats_table.setRowCount(0) + self._copy_button.setEnabled(False) + if not mime_data: + return + + for format in mime_data.formats(): + format_item = QTableWidgetItem(format) + format_item.setFlags(Qt.ItemIsEnabled) + format_item.setTextAlignment(Qt.AlignTop | Qt.AlignLeft) + + if format == "text/plain": + text = simplify_whitespace(mime_data.text()) + elif format == "text/markdown": + text = mime_data.data("text/markdown").data().decode("utf8") + elif format == "text/html": + text = simplify_whitespace(mime_data.html()) + elif format == "text/uri-list": + url_list = mime_data.urls() + text = "" + for i in range(0, min(len(url_list), 32)): + text += url_list[i].toString() + " " + else: + data = mime_data.data(format) + if data.size() > 32: + data.truncate(32) + text = data.toHex(" ").data().decode("utf8").upper() + + row = self._formats_table.rowCount() + self._formats_table.insertRow(row) + self._formats_table.setItem(row, 0, QTableWidgetItem(format)) + self._formats_table.setItem(row, 1, QTableWidgetItem(text)) + + self._formats_table.resizeColumnToContents(0) + self._copy_button.setEnabled(self._formats_table.rowCount() > 0) + + @Slot() + def copy(self): + text = "" + for row in range(0, self._formats_table.rowCount()): + c1 = self._formats_table.item(row, 0).text() + c2 = self._formats_table.item(row, 1).text() + text += f"{c1}: {c2}\n" + QGuiApplication.clipboard().setText(text) diff --git a/examples/widgets/draganddrop/dropsite/main.py b/examples/widgets/draganddrop/dropsite/main.py new file mode 100644 index 000000000..bce476a61 --- /dev/null +++ b/examples/widgets/draganddrop/dropsite/main.py @@ -0,0 +1,15 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import sys + +from PySide6.QtWidgets import QApplication + +from dropsitewindow import DropSiteWindow + + +if __name__ == "__main__": + app = QApplication(sys.argv) + window = DropSiteWindow() + window.show() + sys.exit(app.exec()) |