windows PyQt5可拖动无框窗口

kb5ga3dv  于 2023-01-27  发布在  Windows
关注(0)|答案(6)|浏览(222)

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

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_())
ryoqjall

ryoqjall1#

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

  • 我们需要在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_())
k2arahey

k2arahey2#

这是一个可拖动且可调整大小无框架窗口

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()
lvjbypge

lvjbypge3#

我在GitHub上发布了一个pyqt无框架窗口repo,它在Windows上由pywin32实现,在Linux上由xcffib实现,在macOS上由pyobjc实现。
下面是回购链接:https://github.com/zhiyiYo/PyQt-Frameless-Window

zour9fqk

zour9fqk4#

除了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()
h5qlskok

h5qlskok5#

class Window(QWidget):  
def __init__(self):
    super().__init__() 
    self.center()
    self.oldPos = = self.pos()
    self.isMoveApp = False 
def center(self):
    qr = self.frameGeometry()
    cp = QDesktopWidget().availableGeometry().center()
    qr.moveCenter(cp)
    self.move(qr.topLeft())
    pos = qr.topLeft()
    self.topLabelPos = [pos.x(), pos.y(), pos.x()+720, pos.y()+60]

def mousePressEvent(self, event):
    self.isMoveApp = False
    self.oldPos = event.globalPos()
    x, y = self.oldPos.x(), self.oldPos.y()
    if x > self.topLabelPos[0] and x < self.topLabelPos[2]:
        if y > self.topLabelPos[1] and y < self.topLabelPos[3]:
            self.isMoveApp = True

def mouseMoveEvent(self, event):
    if self.isMoveApp:
        delta = QPoint(event.globalPos() - self.oldPos)
        self.move(self.x() + delta.x(), self.y() + delta.y())
        self.oldPos = event.globalPos()
        x, y = self.topLabelPos[0] + \
            delta.x(), self.topLabelPos[1] + delta.y()
        self.topLabelPos = [x, y, x+720, y+60]

标题标签x = 0 y = 0宽度= 720高度= 60 #单击标题标签可移动应用程序

pdkcd3nj

pdkcd3nj6#

从Qt 5.15开始,你可以使用QWindow的startSystemResize、startSystemMove函数,这让事情变得容易得多。
下面是如何使用它的示例:

def mousePressEvent(self, e):
    if e.button() == Qt.LeftButton:
        if self._resizing:
            self._resize()
        else:
            if self._pressToMove:
                self._move()
        return super().mousePressEvent(e)

def _move(self):
    window = self.window().windowHandle()
    window.startSystemMove()

def _resize(self):
    window = self.window().windowHandle()
    window.startSystemResize(Qt.LeftEdge) // or the other ones

我把这两个函数用到了下面的无框架窗口中,效果很好。
如果你想的话可以去我的仓库看看:https://github.com/yjg30737/pyqt-frameless-window

相关问题