Pyside2 QDialog 背景图形

Pyside2 QDialog Background Graphics

我正在为我的 i3bar/i3blocks 设置制作 dropdown/popup windows。这个想法是在单击某个 i3block 时打开 Qt.Popup 类型 window,它将位于 i3block 上方,看起来像一个弹出菜单。我已经完成了大部分工作,但想像我在图片(红色)中绘制的那样向 Qt window 添加部分边框:

理想情况下,边框不会一直围绕弹出窗口,而是会在弹出窗口“连接”到它延伸的 i3block 的位置停止(示例中的电池 i3block)。然而,边框应该在底部延伸,以将弹出窗口与其他 i3blocks(例如:日历块)分开。这不是我想要制作的唯一弹出窗口,其他人可能或多或少地“挂在”相邻的 i3blocks 上,可能在两侧。边界制动器的开始和结束位置(x 和 y,如果需要)将以 px 为单位。

我研究过使用 QGraphicsView 来简单地绘制这些线条,但无法弄清楚当 window 是 QDialog 时如何让任何 QGraphics 工作。可以添加图形吗?如果可以,怎么做?

注意:我不想使用背景图片,因为我希望无论 window 大小如何,边框线宽度都相同。

相关代码如下:

from PySide2.QtWidgets import * 
from PySide2.QtGui import * 
from PySide2.QtCore import Qt

class Main(QDialog):

    def __init__(self, parent=None):
        super().__init__(parent)

        self.setWindowFlags(Qt.Popup)

        self.setGeometry(0, 0, 50, 100)
        self.setStyleSheet("background-color: #000000; color: #FFFFFF")
        

        #omitted info widgets and layouts would go here
   
        
        layout_main = QVBoxLayout()
        #layout_main.addLayout(layout_TLP)
        #layout_main.addLayout(layout_sleepTime)

        self.setLayout(layout_main)
        self.show()




app = QApplication([])
main = Main()
main.exec_()

QGraphicsView 旨在显示 scene 中列出的 2D 自定义图形,而不是自定义小部件的绘制。为了实现你想要的,你需要使用一个 QPainter created within the paintEvent 的小部件,这是 any 小部件在需要显示时调用的函数。

有各种绘制原始图形的函数,如矩形、椭圆和文本;在你的情况下,你需要使用线条(因为你没有绘制一个完整的矩形)但是,由于单独绘制的线条没有连接,如果边框的宽度大于一个像素,结果可能不会很好,所以你应该选择 drawPolyline.

方法如下:

  • 获取当前widget矩形,从右边和底部减去一个像素,得到实际绘制的矩形;
  • 将矩形缩小 一半 正在绘制的边框的宽度(线条从它们的中间延伸到笔的一半size: 在 y = 10 处绘制的一条宽度为 2 的水平线是从 y = 9y = 11);
  • 获取底边右侧,小线必须“停止”的点;
  • 设置边框的pen(颜色和宽度);
  • 绘制折线;
class Main(QWidget):
    _borderSize = 2
    _bottomWidth = 140
    # ...
    def setBorderSize(self, size):
        self._borderSize = max(1, size)
        self.update()

    def setBottomWidth(self, width):
        self._bottomWidth = max(0, width)
        self.update()

    ​def paintEvent(self, event):
        # the border width could be odd, so we must convert
        # the rectangle to QRectF which supports floating point
        # coordinates, which is also better for QPainter
        rect = QRectF(self.rect().adjusted(0, 0, -1, -1))
        half = self._borderSize / 2
        rect.adjust(half, half, -half, -half)
        bottomLeft = QPointF(rect.left(), rect.bottom() + half)
        bottomRight = QPointF(self._bottomWidth, rect.bottom())

        qp = QPainter(self)
        qp.setRenderHints(qp.Antialiasing)
        qp.setPen(QPen(Qt.red, self._borderSize))
        qp.drawPolyline(QPolygonF((
            bottomLeft,
            rect.topLeft(),
            rect.topRight(),
            rect.bottomRight(),
            bottomRight
        )))

app = QApplication([])
main = Main()
app.exec()

请注意,我继承自 QWidget:因为您覆盖了 window 标志并且您没有使用 window 模式(只有一个 window),所以没有需要一个 QDialog,您可以启动应用程序的事件循环,该循环将在小部件关闭后立即退出。