如何在布局中包含的小部件上绘制线条

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

Windows 11 专业版 PyQt6(最新) Python 3.13.1

我希望这是一件容易的事。我有以下代码:

import sys
from PyQt6.QtCore import QSize, Qt
from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget
# Subclass QMainWindow to customize your application's main window
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("My App")
        layout = QVBoxLayout()
        
        button1 = QPushButton("Press Me!")
        button1.setFixedSize(QSize(200, 60))
        button2 = QPushButton("Press Me!")
        button2.setFixedSize(QSize(200, 60))
        button3 = QPushButton("Press Me!")
        button3.setFixedSize(QSize(200, 60))
        layout.addWidget(button1)
        layout.addWidget(button2)
        layout.addWidget(button3)
        widget = QWidget()
        widget.setLayout(layout)
        #self.setFixedSize(QSize(100, 100))
        # Set the central widget of the Window.
        self.setCentralWidget(widget)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

它运行并产生以下结果:

我想做这个:

我找到下面的代码,它生成了一行。但我不知道如何将该代码与上面的代码合并。这只是一个例子。如果我能弄清楚如何让它在小部件上绘制线条,我可以从那里获取它。到目前为止我有两个要求。 如果可能的话,我需要集成代码能够绘制可以跨越多个小部件的线条。此外,将来我希望能够有一个事件触发器(例如按钮按下)来调用一个函数,该函数会在我的主窗口中的多个小部件上画一条线。

import sys
from PyQt6 import QtCore, QtGui, QtWidgets, uic
from PyQt6.QtCore import Qt


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        self.label = QtWidgets.QLabel()
        canvas = QtGui.QPixmap(400, 300)
        canvas.fill(Qt.GlobalColor.white)
        self.label.setPixmap(canvas)
        self.setCentralWidget(self.label)
        self.draw_something()

    def draw_something(self):
        canvas = self.label.pixmap()
        painter = QtGui.QPainter(canvas)
        painter.drawLine(10, 10, 300, 200)
        painter.end()
        self.label.setPixmap(canvas)


app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
pyqt6
1个回答
0
投票

您不能直接在 over 小部件上绘制,因为渲染遵循堆叠顺序,从下到上:绘制父级,然后在其上方绘制其子级。

解决方案是将一个小部件覆盖在其他小部件之上。 处理布局时会出现问题,因为小部件的几何形状可能会在运行时发生变化(并且在构建小部件时您几乎永远不能依赖初始几何形状)。

只要“栏”必须显示在整个父级上方,那么您就可以使用 QGridLayout,它允许将小部件添加到多个“单元格”,即使它们已经被其他单元格占用。

class BarWidget(QWidget): def __init__(self, parent=None): super().__init__(parent) self.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents) def paintEvent(self, event): qp = QPainter(self) qp.setRenderHint(qp.RenderHint.Antialiasing) qp.setPen(QPen(Qt.GlobalColor.black, 4)) rect = self.rect().adjusted(10, 10, -10, -10) qp.drawLine(rect.topLeft(), rect.bottomRight()) class MainWindow(QMainWindow): def __init__(self): ... barWidget = BarWidget() layout.addWidget( barWidget, 0, 0, layout.rowCount(), layout.columnCount() )

请注意,创建顺序对于堆叠很重要:如果您将该栏小部件添加到其他小部件之前,它将显示在它们下方;在这种情况下,您可以通过调用 
barWidget.raise_()

强制堆叠。 对于可能跨越多个容器或布局的更复杂的情况,唯一的解决方案是在其父窗口(也可能是主窗口)的

resizeEvent()
内手动设置小部件的几何形状:

class MainWindow(QMainWindow): def __init__(self): ... self.barWidget = BarWidget(self) self.barred = button2, button3 def resizeEvent(self, event): super().resizeEvent(event) # this is necessary because we're managing the resize event of the # parent and at this moment the child layout may still not be # activated yet self.centralWidget().layout().activate() self.barWidget.raise_() rect = QRect() for widget in self.barred: geo = widget.rect().translated(widget.mapTo(self, QPoint())) rect |= geo self.barWidget.setGeometry(rect)

    

© www.soinside.com 2019 - 2024. All rights reserved.