简体   繁体   中英

Draggable Frameless PyQt4 Window With A Custom Titlebar

I've managed to make my application draggable using mouseclickevent and mousemoveevent . Here is the current code:

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self, parent)
        self.initUI()

    def initUI(self):
        self.CentralWidget = QtGui.QStackedWidget()
        self.CentralWidget.setFixedHeight(600)
        self.setCentralWidget(self.CentralWidget)
        self.Main = Main(self)
        self.CentralWidget.addWidget(self.Main)
        #Set Current Widgets
        self.CentralWidget.setCurrentWidget(self.Main)
        #Set Background
        self.show()

        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
        self.setStyleSheet("QMainWindow { background-color: \
        rgb(0, 0, 0); }")
        self.setGeometry(0, 0, 850, 600)
        self.setWindowTitle("Folder Locker")
        self.Center()

        Font = QtGui.QFont()
        Font.setPointSize(12)

        TitleBar = QtGui.QDockWidget()

        Actions = QtGui.QGroupBox()

        Title = QtGui.QLabel("Folder Locker")
        Title.setFont(Font)
        Title.setStyleSheet('color: white')
        Title.setAlignment(QtCore.Qt.AlignCenter)

        Fake = QtGui.QPushButton()
        Fake.setFixedWidth(25)
        Fake.setFixedHeight(25)
        Fake.setStyleSheet("QPushButton { background-color: \
        rgb(0, 0, 0); }")
        Fake1 = QtGui.QPushButton()
        Fake1.setFixedWidth(25)
        Fake1.setFixedHeight(25)
        Fake1.setStyleSheet("QPushButton { background-color: \
        rgb(0, 0, 0); }")

        Font = QtGui.QFont()
        Font.setPointSize(12)

        Font2 = QtGui.QFont()
        Font2.setPointSize(18)

        Exit = QtGui.QPushButton("X")
        Exit.setFixedWidth(35)
        Exit.setFixedHeight(25)
        Exit.clicked.connect(self.ExitM)
        Exit.setStyleSheet('QPushButton {background-color: \
        rgb(0, 0, 0); color: grey;}')
        Exit.setFont(Font)

        Minimize = QtGui.QPushButton("-")
        Minimize.setFixedWidth(25)
        Minimize.setFixedHeight(25)
        Minimize.clicked.connect(self.MinimizeM)
        Minimize.setStyleSheet('QPushButton {background-color: \
        rgb(0, 0, 0); color: grey;}')
        Minimize.setFont(Font2)

        Grid = QtGui.QGridLayout()

        Grid.addWidget(Fake, 1, 1)
        Grid.addWidget(Fake1, 1, 2)
        Grid.addWidget(Title, 1, 3)
        Grid.addWidget(Exit, 1, 5)
        Grid.addWidget(Minimize, 1, 4)

        Actions.setLayout(Grid)

        TitleBar.setWidget(Actions)
        TitleBar.setFixedHeight(40)
        TitleBar.setFloating(False)
        TitleBar.setTitleBarWidget(QtGui.QWidget(None))
        TitleBar.setStyleSheet("QGroupBox { background-color: \
        rgb(0, 0, 0); border: 0px solid rgb(0, 0, 0); }")

        self.addDockWidget(QtCore.Qt.TopDockWidgetArea, TitleBar)
        self.oldPos = self.pos()

    def Center(self):
        self.Resolution = QtGui.QDesktopWidget().screenGeometry()
        self.move((self.Resolution.width() / 2) - (self.frameSize().width() / 2),
                  (self.Resolution.height() / 2) - (self.frameSize().height() / 2))

    def MinimizeM(self):
        self.showNormal()
        self.showMinimized()

    def ExitM(self):
        sys.exit(0)

    def mousePressEvent(self, event):
        self.oldPos = event.globalPos()

    def mouseMoveEvent(self, event):
        delta = QtCore.QPoint (event.globalPos() - self.oldPos)
        #print(delta)
        self.move(self.x() + delta.x(), self.y() + delta.y())
        self.oldPos = event.globalPos()

Unfortunately, the window is only draggable by clicking slightly underneath my custom titlebar , I'd like to be able to click the titlebar which is a QDockWidget and for it to cause the window to follow the mouse movement.

Any help would be appreciated, Thank you.

For the problem you describe there are several solutions, one of them might be to activate the Qt::WA_TransparentForMouseEvents attribute of the QDockWidget making the mouse events transparent to pass to the widget below, ie the QMainWindow , but this generates an undesired behavior on the buttons Close and minimize.

So a more elegant solution is to use the eventFilter method and filter the events QEvent::MouseButtonPress and QEvent::MouseMove, but before they must enable the ability to transmit events of the other widget to QMainWindow, in this case we are going to do With TitleBar , Title and self . With this method it is no longer necessary to overwrite the mousePressEvent and mouseMoveEvent methods.

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self, parent)
        self.initUI()

    def initUI(self):
        ...
        TitleBar.installEventFilter(self)
        self.installEventFilter(self)
        Title.installEventFilter(self)

    def eventFilter(self, obj, event):
        if event.type() == QtCore.QEvent.MouseButtonPress:
            self.oldPos = event.globalPos()
        elif event.type() == QtCore.QEvent.MouseMove:
            delta = QtCore.QPoint(event.globalPos() - self.oldPos)
            self.move(self.x() + delta.x(), self.y() + delta.y())
            self.oldPos = event.globalPos()
        return QtGui.QMainWindow.eventFilter(self, obj, event)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM