0

To this question I am referring to the answer from @Kuba Ober Draw Rectangular overlay on QWidget at click

My problem: I dont know how to "translate" the C++ (or C?) into Python. :-(

Thus I ask this "duplicated" question again, and wish anyone would help to rewrite the code to achieve the overlay effect in PyQt5.

As an example, I prepare here some code:

# -*- coding: utf-8 -*-

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

class MyApp(QWidget):
    def __init__(self):
        super(MyApp, self).__init__()
        self.initUI()

    def initUI(self):
        self.text = "hello world"
        self.setGeometry(100, 100, 400, 300)
        self.setWindowTitle('Draw Demo')

        self.btn = QPushButton("Butten should be overlayed", self)
        self.btn.setFixedSize(200, 200)
        self.btn.move(40, 40)

        self.show()

    def paintEvent(self, event):
        qp = QPainter()
        qp.begin(self)
        qp.setPen(QColor(Qt.red))
        qp.setFont(QFont('Arial', 20))

        qp.drawText(10, 50, "hello Python")
        qp.setPen(QColor(Qt.blue))
        qp.drawLine(10, 100, 100, 100)
        qp.drawRect(10, 150, 150, 100)

        qp.setPen(QColor(Qt.red))
        qp.drawEllipse(100, 50, 100, 50)
#        qp.drawPixmap(220, 10, QPixmap("python.jpg"))
        qp.fillRect(200, 175, 150, 100, QBrush(Qt.SolidPattern))
        qp.end()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MyApp()
    window.show()
    sys.exit(app.exec_())

Target is: Let the Button shown in the background (overlayed by QPainter), but it is transparent to mouse event. Thus I could click the button, even though it is covered by QPainter.

Any help will be highly appreciated!

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Rt Rtt
  • 595
  • 2
  • 13
  • 33

1 Answers1

1

The translation from C ++ to Python is simple if we know the equivalences and differences between both languages as I show below:

overLay.py

import sys

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *


class OverLay(QWidget):
    def __init__(self, *args, **kwargs):
        QWidget.__init__(self, *args, **kwargs)
        self.setAttribute(Qt.WA_NoSystemBackground)
        self.setAttribute(Qt.WA_TransparentForMouseEvents)

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.fillRect(self.rect(), QColor(80, 80, 255, 128))

class Filter(QObject):
    def __init__(self, *args, **kwargs):
        QObject.__init__(self, *args, **kwargs)
        self.m_overlay = None
        self.m_overlayOn = None

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


if __name__ == '__main__':
    app = QApplication(sys.argv)
    filt = Filter()
    window = QWidget()
    lay = QHBoxLayout(window)
    for text in ( "Foo", "Bar", "Baz "):
        label = QLabel(text)
        lay.addWidget(label)
        label.installEventFilter(filt)
    window.setMinimumSize(300, 250)
    window.show()
    sys.exit(app.exec_())

Understanding what you want to do in your widget you must use the following code:

main.py

# -*- coding: utf-8 -*-

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

from overlay import Filter


class MyApp(QWidget):
    def __init__(self):
        super(MyApp, self).__init__()
        self.initUI()

    def initUI(self):
        self.text = "hello world"
        self.setGeometry(100, 100, 400, 300)
        self.setWindowTitle('Draw Demo')

        self.btn = QPushButton("Butten should be overlayed", self)
        self.btn.setFixedSize(200, 200)
        self.btn.move(40, 40)
        filt = Filter(self)
        self.btn.installEventFilter(filt)

        self.show()

    [...]

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MyApp()
    window.show()
    sys.exit(app.exec_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Thank you so much! C++ is already very difficult for me, it is more difficult to use C++ to learn Qt. :-) Would you please give me some hint or write the full code in one .py file? As a beginner I prefer to use one py file, cause it is easy for me. Actually I tried with your two files but they dont work. – Rt Rtt Dec 29 '17 at 14:01
  • How are you running the application? Are the files in the same folder? – eyllanesc Dec 29 '17 at 14:02
  • Yes. Both files are saved in the same folder. I replaced your `[...]` part with my original `def paintEvent(self, event)` part. But the button is still shown overlay the Qpainter. – Rt Rtt Dec 29 '17 at 14:07
  • I mean, it works. But the button is shown on top of the Qpainter. – Rt Rtt Dec 29 '17 at 14:09
  • 1
    I only translated the code, I do not understand what you were referring to so it assumes that the solution was that, although I doubt that the code of the previous answer will help what you want to do since it only paints it over the widget, in this case above the button, but it is not painting on top of the window – eyllanesc Dec 29 '17 at 14:11
  • 1
    QPainter is not a widget, it is just a class that is responsible for painting so say "But the button is shown on top of the Qpainter" is not correct. – eyllanesc Dec 29 '17 at 14:12
  • It seems I have referred to another solution. But thank you so much. I try to use your translation to for my target. See if I could work it out. :-) – Rt Rtt Dec 29 '17 at 14:16
  • @eyllanesc: What is the advantage in creating a Filter class instead of using MyApp's own eventFilter method? Is it to increase performance on paintEvents? – musicamante Dec 29 '17 at 17:11
  • 1
    @musicamante The advantage is the modularity, if you overwrite eventFilter for each widget you want it would be copying and pasting too much code, instead you can create your own library and add it there. – eyllanesc Dec 29 '17 at 17:14
  • @eyllanesc: Very interesting, I never thought about that way of using event filters. Thank you! – musicamante Dec 29 '17 at 17:57