Pyqt5:如何限制 QMainWindow 中 QPushButton 的拖动区域?

问题描述

在 QWidget 中拖动 QPushButton 时,它会直到它消失,一旦它通过(跨过)MainWindow (QWidget) 的边界

我想限制这个 QPushButton 不越过它的容器的边界,而是在 QWidget 中保持可见

from PyQt5.QtWidgets import QApplication,QWidget,QPushButton
from PyQt5.QtCore import Qt

class DragButton(QPushButton):
    def mousepressEvent(self,event):
        self.__mousepressPos = None
        self.__mouseMovePos = None
        if event.button() == Qt.LeftButton:
            self.__mousepressPos = event.globalPos()
            self.__mouseMovePos = event.globalPos()
        super(DragButton,self).mousepressEvent(event)

    def mouseMoveEvent(self,event):
        if event.buttons() == Qt.LeftButton:
            # adjust offset from clicked point to origin of widget
            currPos = self.mapToGlobal(self.pos())
            globalPos = event.globalPos()
            diff = globalPos - self.__mouseMovePos
            newPos = self.mapFromGlobal(currPos + diff)
            self.move(newPos)
            self.__mouseMovePos = globalPos
        super(DragButton,self).mouseMoveEvent(event)

    def mouseReleaseEvent(self,event):
        if self.__mousepressPos is not None:
            moved = event.globalPos() - self.__mousepressPos 
            if moved.manhattanLength() > 3:
                event.ignore()
                return
        super(DragButton,self).mouseReleaseEvent(event)

def clicked():
    print ("click as normal!")

if __name__ == "__main__":
    app = QApplication([])
    w   = QWidget()
    w.resize(800,600)
    button = DragButton("Drag",w)
    button.clicked.connect(clicked)
    w.show()
    app.exec_() 

有没有办法做到这一点?

解决方法

由于要求确保子级在父级的边界内,因此您需要检查子级 rect()(翻译到新位置)是否在该区域内,之前 移动它。

请注意,要实现“自我”运动,不必连续平移全局位置。

class DragButton(QPushButton):
    def mousePressEvent(self,event):
        self.__mousePressPos = None
        self.__mouseMovePos = None
        if event.button() == Qt.LeftButton:
            self.__mousePressPos = event.globalPos()
            self.__mouseMovePos = event.pos()
        super(DragButton,self).mousePressEvent(event)

    def mouseMoveEvent(self,event):
        if event.buttons() == Qt.LeftButton:
            delta = event.pos() - self.__mouseMovePos
            newPos = self.pos() + delta
            if self.parent():
                geo = self.rect().translated(newPos)
                parentRect = self.parent().rect()
                if geo.x() < 0:
                    geo.moveLeft(0)
                elif geo.right() > parentRect.right():
                    geo.moveRight(parentRect.right())
                if geo.y() < 0:
                    geo.moveTop(0)
                elif geo.bottom() > parentRect.bottom():
                    geo.moveBottom(parentRect.bottom())
                self.move(geo.topLeft())
            else:
                self.move(newPos)
        super(DragButton,self).mouseMoveEvent(event)

还要考虑拖动已启用的按钮不是一个好主意,因为它可能会导致不需要的、不直观的和意外的行为。您的实现显示了这一点,因为如果按钮移动到超过 3 像素的限制,它将保持按下状态。