【问题标题】:PyQt5 draggable frameless windowPyQt5 可拖动无框窗口
【发布时间】:2016-10-09 15:44:46
【问题描述】:

我找到了一个在无框窗口上设置边框的示例,但它不可拖动。如何使无框窗口可拖动?特别是如果我能看到一个例子,那就太棒了。这是我的示例代码(通常代码较长,这就是为什么有很多库只是不介意它们);

from PyQt5.QtWidgets import (QMessageBox,QApplication, QWidget, QToolTip, QPushButton,
                             QDesktopWidget, QMainWindow, QAction, qApp, QToolBar, QVBoxLayout,
                             QComboBox,QLabel,QLineEdit,QGridLayout,QMenuBar,QMenu,QStatusBar,
                             QTextEdit,QDialog,QFrame,QProgressBar
                             )
from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.QtGui import QIcon,QFont,QPixmap,QPalette
from PyQt5.QtCore import QCoreApplication, Qt,QBasicTimer

import sys

class cssden(QMainWindow):
    def __init__(self):
        super().__init__()


        self.mwidget = QMainWindow(self)
        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)


        #size
        self.setFixedSize(320, 450)
        self.center


        #label
        self.lbl = QLabel(self)
        self.lbl.setText("test")
        self.lbl.setStyleSheet("background-color: rgb(0,0,0);"
                               "border: 1px solid red;"
                               "color: rgb(255,255,255);"
                               "font: bold italic 20pt 'Times New Roman';")
        self.lbl.setGeometry(5,5,60,40)

        self.show()

    #center
    def center(self):
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

app = QApplication(sys.argv)
app.setStyleSheet("QMainWindow{background-color: darkgray;border: 1px solid black}")

ex = cssden()
sys.exit(app.exec_())

【问题讨论】:

    标签: python windows python-3.4 pyqt5 qmainwindow


    【解决方案1】:

    您需要自己处理鼠标事件。

    • 我们需要在mousePressEvent 上添加一个事件,这将保留我们上次单击窗口的位置
    • 然后,我们将添加一个mouseMoveEvent,它将计算上一次点击的点与当前鼠标位置之间的距离。我们将根据这个距离移动窗口。

    这是固定代码:

    import sys
    from PyQt5.QtCore import Qt, QPoint
    from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
    
    
    class cssden(QMainWindow):
        def __init__(self):
            super().__init__()
    
            # <MainWindow Properties>
            self.setFixedSize(320, 450)
            self.setStyleSheet("QMainWindow{background-color: darkgray;border: 1px solid black}")
            self.setWindowFlags(Qt.FramelessWindowHint)
            self.center()
            # </MainWindow Properties>
    
            # <Label Properties>
            self.lbl = QLabel(self)
            self.lbl.setText("test")
            self.lbl.setStyleSheet("QLabel{background-color: rgb(0,0,0); border: 1px solid red; color: rgb(255,255,255); font: bold italic 20pt 'Times New Roman';}")
            self.lbl.setGeometry(5, 5, 60, 40)
            # </Label Properties>
    
            self.oldPos = self.pos()
            self.show()
    
        def center(self):
            qr = self.frameGeometry()
            cp = QDesktopWidget().availableGeometry().center()
            qr.moveCenter(cp)
            self.move(qr.topLeft())
    
        def mousePressEvent(self, event):
            self.oldPos = event.globalPos()
    
        def mouseMoveEvent(self, event):
            delta = QPoint (event.globalPos() - self.oldPos)
            self.move(self.x() + delta.x(), self.y() + delta.y())
            self.oldPos = event.globalPos()
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        ex = cssden()
        sys.exit(app.exec_())
    

    【讨论】:

    • 效果很好。请问有没有关于鼠标悬停等鼠标事件的例子?只有关于 C++ 的示例,我很难将它们转换为 Python。
    • 是的,我知道有很多 Python 示例。我认为最好的方法是了解如何将 Qt C++ 代码转换为 Python。它并不像一开始看起来那么复杂。
    • 这是一个相关的code example
    • 当它完美运行时,我感到非常惊讶。我认为需要对鼠标是否被按下进行某种检查。这让我有点难过,但对于其他想知道的人,我最终在文档中发现:If mouse tracking is switched off (default), mouse move events only occur if a mouse button is pressed while the mouse is being moved. If mouse tracking is switched on, mouse move events occur even if no mouse button is pressed. 所以默认情况下它完成了一半的工作。如果您需要鼠标跟踪,那么您必须稍微更改事件处理程序。
    【解决方案2】:

    这里是可拖动和调整大小的无框窗口

    from PyQt5.QtGui import *
    from PyQt5.QtCore import *
    from PyQt5.QtWidgets import *
    
    
    class movable_label(QLabel):
        def __init__(self, parent):
            super().__init__(parent)
    
            self.parent = parent
    
            self.setStyleSheet("background-color: #ccc")
            self.setMinimumHeight(30)
    
        def mousePressEvent(self, e):
            if e.button() == Qt.LeftButton:
                if self.parent.press_control == 0:
                    self.pos = e.pos()
                    self.main_pos = self.parent.pos()
            super().mousePressEvent(e)
        def mouseMoveEvent(self, e):
            if self.parent.cursor().shape() == Qt.ArrowCursor:
                self.last_pos = e.pos() - self.pos
                self.main_pos += self.last_pos
                self.parent.move(self.main_pos)
            super(movable_label, self).mouseMoveEvent(e)
    
    
    class main(QMainWindow):
        def __init__(self):
            super().__init__()
            
            self.setWindowFlags(Qt.FramelessWindowHint)
            self.central = QWidget()
    
            self.vbox = QVBoxLayout(self.central)
            self.vbox.addWidget(movable_label(self))
            self.vbox.addWidget(QPushButton("Click"))
            self.vbox.setAlignment(Qt.AlignTop)
            self.vbox.setSpacing(0)
            self.vbox.setContentsMargins(0,0,0,0)
            
            self.press_control = 0        
            
            self.setCentralWidget(self.central)
            self.resize(800,500)
            self.show()          
    
        def eventFilter(self, obj, e):
            #hovermoveevent
            if e.type() == 129:
                if self.press_control == 0:
                    self.pos_control(e)#cursor position control for cursor shape setup
    
            #mousepressevent
            if e.type() == 2:
                self.press_control = 1
                self.origin = self.mapToGlobal(e.pos())
                self.ori_geo = self.geometry()
    
            #mousereleaseevent
            if e.type() == 3:
    
                self.press_control = 0
                self.pos_control(e)
            
            #mosuemoveevent
            if e.type() == 5:
                if self.cursor().shape() != Qt.ArrowCursor:
                    self.resizing(self.origin, e, self.ori_geo, self.value)
    
            return True
    
        def pos_control(self, e):
            rect = self.rect()
            top_left = rect.topLeft()
            top_right = rect.topRight()
            bottom_left = rect.bottomLeft()
            bottom_right = rect.bottomRight()
            pos = e.pos()
    
            #top catch
            if pos in QRect(QPoint(top_left.x()+5,top_left.y()), QPoint(top_right.x()-5,top_right.y()+5)):
                self.setCursor(Qt.SizeVerCursor)
                self.value = 1
    
            #bottom catch
            elif pos in QRect(QPoint(bottom_left.x()+5,bottom_left.y()), QPoint(bottom_right.x()-5,bottom_right.y()-5)):
                self.setCursor(Qt.SizeVerCursor)
                self.value = 2
            
            #right catch
            elif pos in QRect(QPoint(top_right.x()-5,top_right.y()+5), QPoint(bottom_right.x(),bottom_right.y()-5)):
                self.setCursor(Qt.SizeHorCursor)
                self.value = 3
    
            #left catch
            elif pos in QRect(QPoint(top_left.x()+5,top_left.y()+5), QPoint(bottom_left.x(),bottom_left.y()-5)):
                self.setCursor(Qt.SizeHorCursor)
                self.value = 4
    
            #top_right catch
            elif pos in QRect(QPoint(top_right.x(),top_right.y()), QPoint(top_right.x()-5,top_right.y()+5)):
                self.setCursor(Qt.SizeBDiagCursor)
                self.value = 5
    
            #botom_left catch
            elif pos in QRect(QPoint(bottom_left.x(),bottom_left.y()), QPoint(bottom_left.x()+5,bottom_left.y()-5)):
                self.setCursor(Qt.SizeBDiagCursor)
                self.value = 6
    
            #top_left catch
            elif pos in QRect(QPoint(top_left.x(),top_left.y()), QPoint(top_left.x()+5,top_left.y()+5)):
                self.setCursor(Qt.SizeFDiagCursor)
                self.value = 7
    
            #bottom_right catch
            elif pos in QRect(QPoint(bottom_right.x(),bottom_right.y()), QPoint(bottom_right.x()-5,bottom_right.y()-5)):
                self.setCursor(Qt.SizeFDiagCursor)
                self.value = 8
            
            #default
            else:
                self.setCursor(Qt.ArrowCursor)       
    
        def resizing(self, ori, e, geo, value):    
            #top_resize
            if self.value == 1:
                last = self.mapToGlobal(e.pos())-ori
                first = geo.height()
                first -= last.y()
                Y = geo.y()
                Y += last.y()
    
                if first > self.minimumHeight():
                    self.setGeometry(geo.x(), Y, geo.width(), first)                    
            
            #bottom_resize
            if self.value == 2:
                last = self.mapToGlobal(e.pos())-ori
                first = geo.height()
                first += last.y()
                self.resize(geo.width(), first)
    
            #right_resize
            if self.value == 3:
                last = self.mapToGlobal(e.pos())-ori
                first = geo.width()
                first += last.x()
                self.resize(first, geo.height())
    
            #left_resize
            if self.value == 4:
                last = self.mapToGlobal(e.pos())-ori
                first = geo.width()
                first -= last.x()
                X = geo.x()
                X += last.x()
    
                if first > self.minimumWidth():
                    self.setGeometry(X, geo.y(), first, geo.height())
    
            #top_right_resize
            if self.value == 5:
                last = self.mapToGlobal(e.pos())-ori
                first_width = geo.width()
                first_height = geo.height()
                first_Y = geo.y()
                first_width += last.x()
                first_height -= last.y()
                first_Y += last.y()
                    
                if first_height > self.minimumHeight():
                    self.setGeometry(geo.x(), first_Y, first_width, first_height)
    
            #bottom_right_resize
            if self.value == 6:
                last = self.mapToGlobal(e.pos())-ori
                first_width = geo.width()
                first_height = geo.height()
                first_X = geo.x()
                first_width -= last.x()
                first_height += last.y()
                first_X += last.x()
                    
                if first_width > self.minimumWidth():
                    self.setGeometry(first_X, geo.y(), first_width, first_height)
    
            #top_left_resize
            if self.value == 7:
                last = self.mapToGlobal(e.pos())-ori
                first_width = geo.width()
                first_height = geo.height()
                first_X = geo.x()
                first_Y = geo.y()
                first_width -= last.x()
                first_height -= last.y()
                first_X += last.x()
                first_Y += last.y()
                    
                if first_height > self.minimumHeight() and first_width > self.minimumWidth():
                    self.setGeometry(first_X, first_Y, first_width, first_height)
    
            #bottom_right_resize
            if self.value == 8:
                last = self.mapToGlobal(e.pos())-ori
                first_width = geo.width()
                first_height = geo.height()
                first_width += last.x()
                first_height += last.y()                    
                
                self.setGeometry(geo.x(), geo.y(), first_width, first_height)           
    
    
    
    app = QApplication([])
    window = main()
    window.installEventFilter(window)
    app.exec()
    

    【讨论】:

      【解决方案3】:

      添加到 Elad Joseph 的回答中,PyQt6 需要更新以下事件:

      def mousePressEvent(self, event):
          self.oldPos = event.globalPosition().toPoint()
      
      def mouseMoveEvent(self, event):
          delta = QPoint (event.globalPosition().toPoint() - self.oldPos)
          self.move(self.x() + delta.x(), self.y() + delta.y())
          self.oldPos = event.globalPosition().toPoint()
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-02-03
        • 1970-01-01
        • 2020-12-19
        • 2016-07-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多