Ruhi Ulusoy
Ruhi Ulusoy

Reputation: 67

Pyqt5 Two QButton Drag and Drop

There are two buttons on the window called Button1 and Button2. In the code below, I can move it by right-clicking the button named Button1. Button1 moves again when I want to right-click and drag Button2. But I can't move Button2 with the code below. I want to move which one of these two buttons right click.How can I do that?

from PyQt5.QtWidgets import QPushButton, QWidget, QApplication
from PyQt5.QtCore import Qt, QMimeData
from PyQt5.QtGui import QDrag
import sys

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):
        super().mousePressEvent(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.button1 = Button('Button1', self)
        self.button1.setFixedSize(100,100)
        self.button1.move(0, 0)

        self.button2 = Button('Button2', self)
        self.button2.move(0, 110)
        self.setWindowTitle('Click or Move')
        self.setGeometry(0, 0, 400, 400)


    def dragEnterEvent(self, e):
        e.accept()

    def dropEvent(self, e):
        position = e.pos()
        print(position)
        self.button1.move(position)
        e.setDropAction(Qt.MoveAction)
        e.accept()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    ex.show()
    app.exec_() 

Upvotes: 0

Views: 184

Answers (1)

musicamante
musicamante

Reputation: 48260

You don't need to subclass a button to move it, and you certainly shouldn't use drag&drop if you're going to move the object within the same parent.

Also, if you're going to check only movements that happen while the right button is pressed, you should always call the base implementation for the other situations (other buttons, or no button, in case mouseTracking is enabled; it's not usually the case with push buttons, but that's not the point).

Install an event filter on the buttons, and track the following events:

  • QEvent.MouseButtonPress: if the button is the right one, set a variable for the current moving widget and another one with the current mouse position (let's say, startPosition)
  • QEvent.MouseMove: if a current moving widget exists, move it using the formula newPosition = currentPosition + eventPosition - startPosition
  • QEvent.MouseButtonRelease: clear the current moving widget
class Example(QWidget):

    def __init__(self):
        super().__init__()

        self.initUI()

        self.movingButton = None

    def initUI(self):

        self.button1 = QPushButton('Button1', self)
        self.button1.setFixedSize(100,100)
        # no need for this, every new widget is always placed at (0, 0)
        # self.button1.move(0, 0)
        self.button1.installEventFilter(self)

        self.button2 = QPushButton('Button2', self)
        self.button2.move(0, 110)
        self.button2.installEventFilter(self)

        self.setWindowTitle('Click or Move')
        self.setGeometry(0, 0, 400, 400)

    def eventFilter(self, source, event):
        if source in (self.button1, self.button2):
            if event.type() == QEvent.MouseButtonPress and event.button() == Qt.RightButton:
                self.movingButton = source
                self.startPos = event.pos()
            # uncomment the following lines if you want to move the button while
            # moving the mouse
            # elif event.type() == QEvent.MouseMove and self.movingButton:
            #     self.movingButton.move(source.pos() + event.pos() - self.startPos)
            elif event.type() == QEvent.MouseButtonRelease and self.movingButton:
                self.movingButton.move(source.pos() + event.pos() - self.startPos)
                self.movingButton = None
        return super().eventFilter(source, event)

Upvotes: 2

Related Questions