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 = 9
到 y = 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,您可以启动应用程序的事件循环,该循环将在小部件关闭后立即退出。
我正在为我的 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 = 9
到y = 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,您可以启动应用程序的事件循环,该循环将在小部件关闭后立即退出。