The example below displays a panel with a couple of widgets with buttons. Once a button is clicked, a semi-transparent blocking layer with an overlay is shown on top of the corresponding parent widget. The overlay is self-contained, reacts to the changes of the parent's size, and renders a simple text in the middle.
It's an updated and polished implementation inspired by @armatita's solution. The code has been tested using qtpy abstract layer with PySide2 installed:
import sys
from typing import Tuple
from qtpy.QtCore import QEvent, QRect, Qt
from qtpy.QtGui import QColor, QPainter, QPalette
from qtpy.QtWidgets import QApplication, QHBoxLayout, QPushButton, QWidget
class TextOverlayWidget(QWidget):
def __init__(
self,
parent: QWidget,
text: str,
overlay_width: int = 300,
overlay_height: int = 150,
):
super().__init__(parent)
self._text = text
self._overlay_width = overlay_width
self._overlay_height = overlay_height
self._TRANSPARENT_COLOR = QColor(0, 0, 0, 0)
self._WINDOW_BACKGROUND_COLOR = QColor(25, 25, 25, 125)
self._OVERLAY_BACKGROUND_COLOR = self.palette().color(QPalette.Base)
parent.installEventFilter(self)
self.setWindowFlags(Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground)
self._add_close_button()
self._resize_to_parent()
def _add_close_button(self):
self._close_button = QPushButton(self)
self._close_button.setText("x")
self._close_button.setFixedSize(30, 30)
font = self._close_button.font()
font.setPixelSize(15)
self._close_button.setFont(font)
self._close_button.clicked.connect(lambda: self.close())
def eventFilter(self, obj, event) -> bool:
if event.type() == QEvent.Resize:
self._resize_to_parent()
return super().eventFilter(obj, event)
def _resize_to_parent(self):
self.move(0, 0)
self.resize(self.parent().width(), self.parent().height())
overlay_corner_width, overlay_corner_height = self._get_overlay_corner()
self._close_button.move(
overlay_corner_width + self._overlay_width - self._close_button.width(),
overlay_corner_height,
)
def _get_window_size(self) -> Tuple[int, int]:
size = self.size()
return size.width(), size.height()
def _get_overlay_corner(self) -> Tuple[int, int]:
width, height = self._get_window_size()
overlay_corner_width = int(width / 2 - self._overlay_width / 2)
overlay_corner_height = int(height / 2 - self._overlay_height / 2)
return overlay_corner_width, overlay_corner_height
def paintEvent(self, event):
painter = QPainter()
painter.begin(self)
painter.setRenderHint(QPainter.Antialiasing, True)
painter.setPen(self._TRANSPARENT_COLOR)
painter.setBrush(self._WINDOW_BACKGROUND_COLOR)
width, height = self._get_window_size()
painter.drawRect(0, 0, width, height)
painter.setPen(self._TRANSPARENT_COLOR)
painter.setBrush(self._OVERLAY_BACKGROUND_COLOR)
rounding_radius = 5
overlay_rectangle = QRect(
*self._get_overlay_corner(), self._overlay_width, self._overlay_height
)
painter.drawRoundedRect(overlay_rectangle, rounding_radius, rounding_radius)
font = self.font()
font.setPixelSize(20)
painter.setFont(font)
painter.setPen(QColor(0, 0, 0))
painter.drawText(overlay_rectangle, Qt.AlignCenter, self._text)
painter.end()
class MainWindow(QWidget):
def __init__(self, parent: QWidget = None):
super().__init__(parent)
layout = QHBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
layout.addWidget(self._create_button_widget("Hello!", 200, False))
layout.addWidget(self._create_button_widget("Hola!", 200, False))
layout.addWidget(
self._create_button_widget("Hi in the whole window!", 400, True)
)
self.setLayout(layout)
def _create_button_widget(
self, text: str, overlay_width: int, show_on_full_window: bool
):
widget = QWidget()
widget.setMinimumWidth(300)
widget.setMinimumHeight(500)
button = QPushButton(f"Say '{text}'")
overlay_parent = self if show_on_full_window else widget
button.clicked.connect(
lambda: TextOverlayWidget(overlay_parent, text, overlay_width).show()
)
layout = QHBoxLayout()
layout.addWidget(button)
widget.setLayout(layout)
return widget
if __name__ == "__main__":
app = QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())
Sample text overlay
The example above is available in the GitHub repository: https://github.com/machur/qt-extra-widgets/blob/main/examples/text_overlay_widget_example.py