Быстрый в изучении - мощный в программировании
>> Telegram ЧАТ для Python Программистов

Свободное общение и помощь советом и решением проблем с кодом! Заходите в наш TELEGRAM ЧАТ!

>> Python Форум Помощи!

Мы создали форум где отвечаем на все вопросы связанные с языком программирования Python. Ждем вас там!

>> Python Канал в Telegram

Обучающие статьи, видео и новости из мира Python. Подпишитесь на наш TELEGRAM КАНАЛ!

Перетаскивание «Drag’n’drop» в PyQt5 [Урок №9]

Перетаскивание «Drag’n’drop» в PyQt5

В этой части руководства по PyQt5, мы поговорим об операциях перетаскивания. В графических интерфейсах, Drag’n’drop – это действие (или поддержка для действия) клика на виртуальный объект и перетаскивания его в другое положение или в другой виртуальный объект. В общем, это может быть использовано, чтобы запускать множество видов действий, или создавать различные типы ассоциаций между двумя абстрактными объектами.

Drag’n’drop – это часть графического пользовательского интерфейса. Операции перетаскивания позволяют пользователям делать сложные вещи интуитивно.

Обычно, мы можем перетаскивать две вещи: данные или некие графические объекты. Если мы перетаскиваем изображение из одного приложения в другое, мы перетаскиваем двоичные данные. Если мы перетаскиваем таблицу в Firefox и перемещаем её в другое место, мы перетаскиваем графический компонент.

Простое перетаскивание

В первом примере, мы имеем QLineEdit и QPushButton. Мы перетаскиваем простой текст из виджета строки редактирования и помещаем его в виджет кнопки. Метка кнопки изменится.

#!/usr/bin/python3
# -*- coding: utf-8 -*-
 
import sys
from PyQt5.QtWidgets import (QPushButton, QWidget, QLineEdit, QApplication)
 
class Button(QPushButton):
  
    def __init__(self, title, parent):
        super().__init__(title, parent)
        self.setAcceptDrops(True)
        
    def dragEnterEvent(self, e):
        if e.mimeData().hasFormat('text/plain'):
            e.accept()
        else:
            e.ignore() 
    def dropEvent(self, e):
        self.setText(e.mimeData().text()) 
 
class Example(QWidget):
  
    def __init__(self):
        super().__init__()
        self.initUI()
        
    def initUI(self):
        edit = QLineEdit('', self)
        edit.setDragEnabled(True)
        edit.move(30, 65)
        button = Button("Button", self)
        button.move(190, 65)
        
        self.setWindowTitle('Simple drag & drop')
        self.setGeometry(300, 300, 300, 150)
 
if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    ex.show()
    app.exec_()

Пример представляет простую операцию перетаскивания.

class Button(QPushButton):
  
    def __init__(self, title, parent):
        super().__init__(title, parent)
        self.setAcceptDrops(True)

Для того, чтобы перетащить текст на виджет QPushButton, мы должны переопределить несколько методов. По этой причине, мы создаём наш собственный класс Button, который будет наследовать класс QPushButton.

self.setAcceptDrops(True)

Мы делаем возможными события перетаскивания для виджета.

def dragEnterEvent(self, e):
    if e.mimeData().hasFormat('text/plain'):
        e.accept()
    else:
        e.ignore()

Сначала, мы переопределяем метод dragEnterEvent(). Мы сообщаем о типе данных, который мы допускаем. В нашем случае, это обычный текст.

def dropEvent(self, e):
    self.setText(e.mimeData().text())

Путём переопределения метода dropEvent, мы определяем, что мы должны делать после события перетаскивания. Здесь мы меняем текст виджета кнопки.

edit = QLineEdit('', self)
edit.setDragEnabled(True)

Виджет QLineEdit имеет встроенную поддержку операций перетаскивания. Все, что нам необходимо сделать – это вызвать метод setDragEnabled(), чтобы активировать её.

Простое перетаскивание

Рисунок: Простое перетаскивание

Перетаскивание виджета кнопки

В следующем примере, мы продемонстрируем, как перетаскивать виджет кнопки.

#!/usr/bin/python3
# -*- coding: utf-8 -*-
 
import sys
from PyQt5.QtWidgets import QPushButton, QWidget, QApplication
from PyQt5.QtCore import Qt, QMimeData
from PyQt5.QtGui import QDrag
 
class Button(QPushButton):
  
    def __init__(self, title, parent):
        super().__init__(title, parent)
 
    def mouseMoveEvent(self, e):
        if e.buttons() != Qt.RightButton:
            return
 
        mimeData = QMimeData()
 
        drag = QDrag(self)
        drag.setMimeData(mimeData)
        drag.setHotSpot(e.pos() - self.rect().topLeft())
 
        dropAction = drag.exec_(Qt.MoveAction)
 
    def mousePressEvent(self, e):
        QPushButton.mousePressEvent(self, e)
        if e.button() == Qt.LeftButton:
            print('press')
 
class Example(QWidget):
  
    def __init__(self):
        super().__init__()
        self.initUI()
        
    def initUI(self):
        self.setAcceptDrops(True)
 
        self.button = Button('Button', self)
        self.button.move(100, 65)
        self.setWindowTitle('Click or Move')
        self.setGeometry(300, 300, 280, 150)
        
    def dragEnterEvent(self, e):
        e.accept()
        
    def dropEvent(self, e):
        position = e.pos()
        self.button.move(position)
        e.setDropAction(Qt.MoveAction)
        e.accept()
        
if __name__ == '__main__':
  
    app = QApplication(sys.argv)
    ex = Example()
    ex.show()
    app.exec_()

В нашем примере кода, мы имеем QPushButton в окне. Если мы кликаем на кнопку левой кнопкой мыши, сообщение «нажата» печатается в консоли. С помощью правого клика и перемещения кнопки, мы выполняем операцию перетаскивания на виджет кнопки.

class Button(QPushButton):
    def __init__(self, title, parent):
        super().__init__(title, parent)

Мы создаём класс Button, который происходит из QPushButton. Мы также переопределяем два метода QPushButton: mouseMoveEvent() и mousePressEvent(). Метод mouseMoveEvent() – это место, где операция перетаскивания начинается.

if e.buttons() != Qt.RightButton:
    return

Здесь мы решаем, что мы можем выполнять перетаскивание только с помощью правой кнопки мыши. Левая кнопка мыши резервируется для нажатия на кнопку.

mimeData = QMimeData()
 
drag = QDrag(self)
drag.setMimeData(mimeData)
drag.setHotSpot(e.pos() - self.rect().topLeft())
Создаётся объект QDrag. Класс обеспечивает поддержку для перемещения основанных на MIME перетаскиваемых данных.
dropAction = drag.exec_(Qt.MoveAction)

Метод start() объекта перетаскивания начинает операцию Drag’n’drop.

def mousePressEvent(self, e):
    QPushButton.mousePressEvent(self, e)
    if e.button() == Qt.LeftButton:
        print('press')

Мы печатаем «нажата» в консоли, если мы делаем левый клик мышкой на кнопку. Обратите внмание, что мы также вызываем метод mousePressEvent() в родителе. В противном случае, мы не увидим, что кнопка была нажата.

position = e.pos()
self.button.move(position)

В методе dropEvent(), мы закодировали, что произойдёт после того, как мы отпустим кнопку мыши и завершим операцию перетаскивания. Мы выясняем текущее положение указателя мыши и перемещаем кнопку соответствующим образом.

e.setDropAction(Qt.MoveAction)
e.accept()

Мы указываем тип действия перетаскивания. В нашем случае, это действие перемещения.

Эта часть руководства PyQt5 была посвящена операциям Drag’n’Drop.

Комментариев: 1
  1. Если статья еще поддержываеться, то большая просьба более детально описать метод mouseMoveEvent, непонятно на счет обьектов QMimeData, QDrag