Python 如何在Qt中在小部件上绘制形状

Python 如何在Qt中在小部件上绘制形状,python,qt,pyqt,pyqt5,Python,Qt,Pyqt,Pyqt5,我试图在一个小部件上绘制一个形状,据我所知,您可以通过重写paintEvent()方法来实现这一点。但是,当我这样做时,形状是在后面渲染的。如何渲染前面的形状? 我正在使用pyqt5,我的测试代码是: from PyQt5 import Qt from PyQt5.QtGui import QPainter, QPen,QBrush,QColor from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QApplication, QMain

我试图在一个小部件上绘制一个形状,据我所知,您可以通过重写
paintEvent()
方法来实现这一点。但是,当我这样做时,形状是在后面渲染的。如何渲染前面的形状? 我正在使用pyqt5,我的测试代码是:

from PyQt5 import Qt
from PyQt5.QtGui import QPainter, QPen,QBrush,QColor
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QHBoxLayout,QPushButton
import sys

class MyWidget(QWidget):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.btn = QPushButton('Hello World')
        self.layout = QHBoxLayout()
        self.layout.addWidget(self.btn)
        self.setLayout(self.layout)

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setPen(QPen(Qt.green))
        brush = QBrush(QColor(0,0,255,255))
        painter.setBrush(brush)
        painter.drawRect(0,0,50,50)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    mainscreen = MyWidget()
    mainscreen.show()
    app.exec_()

Qt小部件从父级绘制到子级。 这意味着
MyWidget
QPushButton
绘制自身之前绘制自身(通过调用
paintEvent()


一种可能的解决方案是创建一个小部件来绘制矩形,并使其成为
QPushButton
的同级(即
MyWidget
的子级)。然后,您可以通过使用
QWidget::stackUnder()
QWidget::raise()
QWidget::lower()
QWidget::lower()

将Qt小部件从父对象绘制到子对象,来决定
QPushButton
RectangleWidget
的呈现顺序。 这意味着
MyWidget
QPushButton
绘制自身之前绘制自身(通过调用
paintEvent()


一种可能的解决方案是创建一个小部件来绘制矩形,并使其成为
QPushButton
的同级(即
MyWidget
的子级)。然后,您可以通过使用
QWidget::stackUnder()
QWidget::raise()
QWidget::lower()
QWidget::lower()
这本质上是一个常见问题的Python版本:如何在小部件上覆盖内容。我有一系列相关的答案:

第三个答案,用Python重铸:

# https://github.com/KubaO/stackoverflown/tree/master/questions/python-overlay-49920532
from PyQt5 import Qt
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys

class Overlay(QWidget):
    def __init__(self, parent = None):
        QWidget.__init__(self, parent)
        self.setAttribute(Qt.WA_NoSystemBackground)
        self.setAttribute(Qt.WA_TransparentForMouseEvents)

    def paintEvent(self, event) {
        QPainter(self).fillrect(self.rect(), QColor(80, 80, 255, 128))

class Filter(QObject):
    def __init__(self, parent = None):
        QObject.__init__(self, parent)
        self.m_overlay = None
        self.m_overlayOn = None

    def eventFilter(self, w, event):
        if w.isWidgetType():
            if event.type() == QEvent.MouseButtonPress:
                if not m_overlay:
                    m_overlay = Overlay(w.parentWidget());
                    m_overlay.setGeometry(w.geometry());
                    m_overlayOn = w;
                    m_overlay.show();
            elif event.type() == QEvent.Resize:
                if m_overlay and m_overlayOn is w:
                    m_overlay.setGeometry(w.geometry());
        return False

if __name__ == "__main__":
    app = QApplication(sys.argv)
    filter = Filter()
    window = QWidget()
    layout = QHBoxLayout(window);
    for text in ["Foo", "Bar", "Baz"]:
        label = QLabel(text)
        label.installEventFilter(filter)
        layout.addWidget(label)
    window.setMinimumSize(300, 250)
    window.show()
    app.exec_()

这本质上是一个常见问题的Python版本:如何在小部件上覆盖内容。我有一系列相关的答案:

第三个答案,用Python重铸:

# https://github.com/KubaO/stackoverflown/tree/master/questions/python-overlay-49920532
from PyQt5 import Qt
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys

class Overlay(QWidget):
    def __init__(self, parent = None):
        QWidget.__init__(self, parent)
        self.setAttribute(Qt.WA_NoSystemBackground)
        self.setAttribute(Qt.WA_TransparentForMouseEvents)

    def paintEvent(self, event) {
        QPainter(self).fillrect(self.rect(), QColor(80, 80, 255, 128))

class Filter(QObject):
    def __init__(self, parent = None):
        QObject.__init__(self, parent)
        self.m_overlay = None
        self.m_overlayOn = None

    def eventFilter(self, w, event):
        if w.isWidgetType():
            if event.type() == QEvent.MouseButtonPress:
                if not m_overlay:
                    m_overlay = Overlay(w.parentWidget());
                    m_overlay.setGeometry(w.geometry());
                    m_overlayOn = w;
                    m_overlay.show();
            elif event.type() == QEvent.Resize:
                if m_overlay and m_overlayOn is w:
                    m_overlay.setGeometry(w.geometry());
        return False

if __name__ == "__main__":
    app = QApplication(sys.argv)
    filter = Filter()
    window = QWidget()
    layout = QHBoxLayout(window);
    for text in ["Foo", "Bar", "Baz"]:
        label = QLabel(text)
        label.installEventFilter(filter)
        layout.addWidget(label)
    window.setMinimumSize(300, 250)
    window.show()
    app.exec_()

对不起,“在前面”是什么意思?你能添加一张显示所需结果的模型图片吗?@S.monteleon谢谢你的回复,我已经上传了一张样本图片谢谢,现在一切都清楚了。您希望在所有小部件的顶部绘制红方块。那么@BenjaminT的答案是正确的,很抱歉,你说的“在前面”是什么意思?你能添加一张显示所需结果的模型图片吗?@S.monteleon谢谢你的回复,我已经上传了一张样本图片谢谢,现在一切都清楚了。您希望在所有小部件的顶部绘制红方块。那么@BenjaminT的答案是正确的,可能是重复的谢谢,我尝试了两种解决方案,它们都对我有效。@恢复Monica此答案中提到的python解决方案非常有缺陷。@Raj我不太知道这样简单的代码怎么会有“缺陷”-要么有效,要么无效。如果您有任何特殊的问题,请分享一个指向复制机的主要链接,我来看看。考虑到这是C++代码的直接翻译,我希望两者都是“Bug”。谢谢,我尝试了这两种解决方案,它们都为我工作。“恢复莫尼卡,Python解决方案中提到的答案非常多。”我不知道这些简单的代码是如何“Bugy”的——它可以工作,也不会。如果您有任何特殊的问题,请分享一个指向复制机的主要链接,我来看看。考虑到它是C++代码的直接翻译,那么我希望两者都是“Bug”。你能举个例子吗?
QWidget::lower()
似乎不起作用(或者更可能是我把继承人制度搞砸了)。你能举个例子吗。
QWidget::lower()
似乎不起作用(或者更可能是我把继承人的档案搞砸了)。