pyQT6 创建一个透明的普通框架窗口,总是在顶部,可以调整大小,可以用顶部栏拖动(仅限 Windows)

问题描述 投票:0回答:0

我正在尝试在屏幕上绘制覆盖图,让用户捕获有关屏幕上元素的详细信息。

抱歉,如果这真的很简单,我整个上午都在笨手笨脚地想弄明白。

我目前正在尝试这个,我猜我不太了解主窗口和嵌套窗口的细微差别,这导致了我的挣扎: https://forum.qt.io/topic/93408/transparent-widget/12

我想要的功能是:

  1. 适用于 PyQT6
  2. 正常的窗口
  3. 正常的拖动移动行为
  4. 正常调整大小行为
  5. 完全不透明的窗口顶栏和框架边框
  6. 不是 [setWindowOpacity(.8)]
  7. 框架的完全透明内容
  8. 如果只能在 Windows 上运行就可以了

我正在寻找与此类似的东西:https://i.stack.imgur.com/eu68P.png

来自: Qt - 在不使用 WA_TranslucentBackground 的情况下在 Windows 中绘制一个完全透明的窗口

我知道 BlurBehindWindow 不再可用。

无论我设置什么,我总是得到一个黑色背景的窗口。 如果我启用“FramelessWindowHint”,我会得到我想要的透明行为,但我无法拖动我的窗口或调整它的大小。

所以我发现了另一篇关于堆栈溢出的帖子,它添加了调整无框窗口大小的句柄,但是当你移动左侧时,它有点丑陋,右侧跳来跳去,并且随着它以一种令人不快的方式调整大小而抖动。

这是我尝试过的所有突变

import sys
from PyQt6.QtGui import QPainter, QPen, QColor, QBitmap
from PyQt6.QtWidgets import QMainWindow, QApplication, QWidget
from PyQt6.QtCore import Qt

class Clear(QMainWindow):

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

        self.initUI()

    def initUI(self):
        self.setGeometry(300, 300, 280, 270)
        #self.setStyleSheet("background:transparent")
        #self.setWindowFlags(Qt.WindowType(0x00000800))
        #self.setWindowOpacity(.8)
        #self.setWindowFlags(Qt.WindowType.Window)
        #self.setWindowFlags(Qt.WindowType.WindowType_Mask)
        self.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
        #self.setWindowFlags(Qt.WindowType.WindowTransparentForInput)
        self.setWindowFlags(Qt.WindowType.FramelessWindowHint)
        #self.autoFillBackground()
        #self.setAttribute(Qt.WidgetAttribute.WA_NoSystemBackground)
        self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
        #self.setAttribute(Qt.WidgetAttribute.WA_OpaquePaintEvent, False)
        #self.setStyleSheet("background:transparent")
        #self.setStyleSheet("background-color: rgba(0, 0, 0, 0)")
        #self.setAttribute(Qt.WidgetAttribute.WA_X11OpenGLOverlay)
        #self.setAttribute(Qt.WidgetAttribute.WA_StyledBackground)
        #self.setAttribute(Qt.WidgetAttribute.WA_)
        #self.setWindowFlags(Qt.WindowType.WindowTitleHint)
        self.show()


    def paintEvent(self, e):
        qp = QPainter()
        qp.backgroundMode()
        qp.begin(self)
        self.drawLines(qp)
        qp.end()

    def drawLines(self, qp):
        pen = QPen(QColor('blue'), 2, Qt.PenStyle.SolidLine)

        qp.setPen(pen)
        qp.drawLine(20, 40, 250, 40)

        pen.setStyle(Qt.PenStyle.DashLine)
        qp.setPen(pen)
        qp.drawLine(20, 80, 250, 80)

        pen.setStyle(Qt.PenStyle.DashDotLine)
        qp.setPen(pen)
        qp.drawLine(20, 120, 250, 120)

        pen.setStyle(Qt.PenStyle.DotLine)
        qp.setPen(pen)
        qp.drawLine(20, 160, 250, 160)

        pen.setStyle(Qt.PenStyle.DashDotDotLine)
        qp.setPen(pen)
        qp.drawLine(20, 200, 250, 200)

        pen.setStyle(Qt.PenStyle.CustomDashLine)
        pen.setDashPattern([1, 4, 5, 4])
        qp.setPen(pen)
        qp.drawLine(20, 240, 250, 240)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = Clear()
    sys.exit(app.exec())

这是无框的,在调整大小时会出现抖动行为,并且顶部没有拖动条。


from PyQt6 import QtCore, QtGui, QtWidgets
import sys
from PyQt6.QtGui import QPainter, QPen, QColor, QBitmap
#from PyQt6.QtWidgets import QMainWindow, QApplication
from PyQt6.QtCore import Qt


class SideGrip(QtWidgets.QWidget):
    def __init__(self, parent, edge):
        QtWidgets.QWidget.__init__(self, parent)
        if edge == QtCore.Qt.Edge.LeftEdge:
            self.setCursor(QtCore.Qt.CursorShape.SizeHorCursor)
            self.resizeFunc = self.resizeLeft
        elif edge == QtCore.Qt.Edge.TopEdge:
            self.setCursor(QtCore.Qt.CursorShape.SizeVerCursor)
            self.resizeFunc = self.resizeTop
        elif edge == QtCore.Qt.Edge.RightEdge:
            self.setCursor(QtCore.Qt.CursorShape.SizeHorCursor)
            self.resizeFunc = self.resizeRight
        else:
            self.setCursor(QtCore.Qt.CursorShape.SizeVerCursor)
            self.resizeFunc = self.resizeBottom
        self.mousePos = None

    def resizeLeft(self, delta):
        window = self.window()
        width = max(window.minimumWidth(), window.width() - delta.x())
        geo = window.geometry()
        geo.setLeft(geo.right() - width)
        window.setGeometry(geo)

    def resizeTop(self, delta):
        window = self.window()
        height = max(window.minimumHeight(), window.height() - delta.y())
        geo = window.geometry()
        geo.setTop(geo.bottom() - height)
        window.setGeometry(geo)

    def resizeRight(self, delta):
        window = self.window()
        width = max(window.minimumWidth(), window.width() + delta.x())
        window.resize(width, window.height())

    def resizeBottom(self, delta):
        window = self.window()
        height = max(window.minimumHeight(), window.height() + delta.y())
        window.resize(window.width(), height)

    def mousePressEvent(self, event):
        if event.button() == QtCore.Qt.MouseButton.LeftButton:
            self.mousePos = event.pos()

    def mouseMoveEvent(self, event):
        if self.mousePos is not None:
            delta = event.pos() - self.mousePos
            self.resizeFunc(delta)

    def mouseReleaseEvent(self, event):
        self.mousePos = None


class Main(QtWidgets.QMainWindow):
    _gripSize = 8
    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)

        #toggle this to make frameless,
        # but the Frameless is really ugly when resizing, the sides jump around.
        self.setWindowFlags(QtCore.Qt.WindowType.FramelessWindowHint)

        self.sideGrips = [
            SideGrip(self, QtCore.Qt.Edge.LeftEdge),
            SideGrip(self, QtCore.Qt.Edge.TopEdge),
            SideGrip(self, QtCore.Qt.Edge.RightEdge),
            SideGrip(self, QtCore.Qt.Edge.BottomEdge),
        ]
        # corner grips should be "on top" of everything, otherwise the side grips
        # will take precedence on mouse events, so we are adding them *after*;
        # alternatively, widget.raise_() can be used
        self.cornerGrips = [QtWidgets.QSizeGrip(self) for i in range(4)]

    @property
    def gripSize(self):
        return self._gripSize

    def setGripSize(self, size):
        if size == self._gripSize:
            return
        self._gripSize = max(2, size)
        self.updateGrips()

    def updateGrips(self):
        self.setContentsMargins(*[self.gripSize] * 4)

        outRect = self.rect()
        # an "inner" rect used for reference to set the geometries of size grips
        inRect = outRect.adjusted(self.gripSize, self.gripSize,
            -self.gripSize, -self.gripSize)

        # top left
        self.cornerGrips[0].setGeometry(
            QtCore.QRect(outRect.topLeft(), inRect.topLeft()))
        # top right
        self.cornerGrips[1].setGeometry(
            QtCore.QRect(outRect.topRight(), inRect.topRight()).normalized())
        # bottom right
        self.cornerGrips[2].setGeometry(
            QtCore.QRect(inRect.bottomRight(), outRect.bottomRight()))
        # bottom left
        self.cornerGrips[3].setGeometry(
            QtCore.QRect(outRect.bottomLeft(), inRect.bottomLeft()).normalized())

        # left edge
        self.sideGrips[0].setGeometry(
            0, inRect.top(), self.gripSize, inRect.height())
        # top edge
        self.sideGrips[1].setGeometry(
            inRect.left(), 0, inRect.width(), self.gripSize)
        # right edge
        self.sideGrips[2].setGeometry(
            inRect.left() + inRect.width(),
            inRect.top(), self.gripSize, inRect.height())
        # bottom edge
        self.sideGrips[3].setGeometry(
            self.gripSize, inRect.top() + inRect.height(),
            inRect.width(), self.gripSize)

    def resizeEvent(self, event):
        QtWidgets.QMainWindow.resizeEvent(self, event)
        self.updateGrips()


app = QtWidgets.QApplication([])
m = Main()
m.show()
m.resize(240, 160)
sys.exit(app.exec())
python pyqt pyqt6
© www.soinside.com 2019 - 2024. All rights reserved.