【问题标题】:How to draw shape over a widget in Qt如何在 Qt 中的小部件上绘制形状
【发布时间】:2018-09-29 22:12:01
【问题描述】:

我正在尝试在小部件上绘制一个形状,据我了解,您可以通过覆盖 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_()

【问题讨论】:

  • 对不起,“在前面”是什么意思?您可以添加显示所需结果的样机图片吗?
  • @S.Monteleone 感谢您的回复,我已经上传了示例图片
  • 谢谢,现在很清楚了。您想在所有小部件的顶部绘制红色方块。那么@BenjaminT 的答案是正确的

标签: python qt pyqt pyqt5


【解决方案1】:

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

一种可能的解决方案是创建一个小部件来绘制矩形并使其成为QPushButton 的兄弟(即MyWidget 的子级)。然后您可以使用QWidget::stackUnder()QWidget::raise()QWidget::lower() 来决定QPushButtonRectangleWidget 的渲染顺序。

【讨论】:

  • 你能举个例子吗? QWidget::lower() 似乎不起作用(或者更可能我只是搞砸了层次结构)。
【解决方案2】:

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

第三个答案,用 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_()

【讨论】:

  • 谢谢,我尝试了这两种解决方案,它们都对我有用。
  • @Reinstate Monica 这个答案中提到的python解决方案非常有问题。
  • @Raj 我不太清楚这么简单的代码怎么会“有问题”——它要么工作要么不工作。如果您有任何特殊问题,请分享指向复制者的要点链接,我会看看。鉴于它是 C++ 代码的直接翻译,那么我希望两者都是“错误的”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-29
  • 2012-09-01
  • 2017-01-30
  • 1970-01-01
相关资源
最近更新 更多