1

I'm trying to draw a shape over a widget and from what I understand you can do this by overriding the paintEvent() method. However, when I do so, the shape is rendered at the back. How can I render the shape in front? I'm using pyqt5 and my test code is:

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_()

enter image description here

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Ijlal
  • 159
  • 2
  • 13

2 Answers2

3

Qt widgets are drawn from parent to children. That means that MyWidget paints itself (by calling paintEvent()) before the QPushButton paints itself.

One possible solution is to create a widget to draw the rectangle and make it a sibling of QPushButton (i.e child of MyWidget). You can then decide of the rendering order of QPushButton and RectangleWidget by using QWidget::stackUnder(), QWidget::raise() or QWidget::lower().

Benjamin T
  • 8,120
  • 20
  • 37
  • Can you please provide an example. The `QWidget::lower()` doesn't seem to work (or more probably I just messed up the heirarchies). – Raj Apr 15 '20 at 19:21
2

This is essentially a Python version of a common problem: how to overlay stuff over the widgets. I have a series of overlay-related answers: first, second, third.

The third answer, recast in 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_()
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • Thanks , I tried both solutions and they both work for me. – Ijlal Apr 19 '18 at 14:08
  • @Reinstate Monica The python solution mentioned in this answer is very much buggy. – Raj Apr 15 '20 at 18:45
  • @Raj I don't quite know how such simple code can be "buggy" - it'll either work or it won't. If there are any particular problems you have, share a gist link to a reproducer and I'll take a look. Given that it is a direct translation of the C++ code, then I'd expect both to be "buggy". – Kuba hasn't forgotten Monica Apr 15 '20 at 21:48