Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PyQt5: Create semi-transparent window with non-transparent children

I want to create a fullscreen window with semitransparent background, but fully visible children widgets (kind of overlay effect).

Here's what I have so far:

import sys

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

app = QApplication(sys.argv)

# Create the main window
window = QMainWindow()

window.setWindowOpacity(0.3)
window.setAttribute(Qt.WA_NoSystemBackground, True)
window.setWindowFlags(Qt.FramelessWindowHint)

# Create the button
pushButton = QPushButton(window)
pushButton.setGeometry(QRect(240, 190, 90, 31))
pushButton.setText("Finished")
pushButton.clicked.connect(app.quit)

# Center the button
qr = pushButton.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
pushButton.move(qr.topLeft())

# Run the application
window.showFullScreen()
sys.exit(app.exec_())

This creates a semi-transparent effect, but even the button is semi-transparent.

I also tried to substitute the

window.setWindowOpacity(0.3)

with this call

window.setAttribute(Qt.WA_TranslucentBackground, True)

but to no avail, in this case the background was fully transparent (while the button was correctly fully visible).

Solution: (implemented thanks to Aaron's suggestion):

The trick is in implementing a custom paintEvent for the main window.

import sys

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

class CustomWindow(QMainWindow):
    def paintEvent(self, event=None):
        painter = QPainter(self)

        painter.setOpacity(0.7)
        painter.setBrush(Qt.white)
        painter.setPen(QPen(Qt.white))   
        painter.drawRect(self.rect())


app = QApplication(sys.argv)

# Create the main window
window = CustomWindow()

window.setWindowFlags(Qt.FramelessWindowHint)
window.setAttribute(Qt.WA_NoSystemBackground, True)
window.setAttribute(Qt.WA_TranslucentBackground, True)

# Create the button
pushButton = QPushButton(window)
pushButton.setGeometry(QRect(240, 190, 90, 31))
pushButton.setText("Finished")
pushButton.clicked.connect(app.quit)

# Center the button
qr = pushButton.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
pushButton.move(qr.topLeft())

# Run the application
window.showFullScreen()
sys.exit(app.exec_())
like image 866
Enuy Avatar asked Nov 29 '15 11:11

Enuy


2 Answers

Ok, while is seems not to work with the available flags you can still use Qt.WA_TranslucentBackground because it is possible to draw a semitranparent rect on that transparency.

Derive your mainwindow from QMainWindow and use that class instead.

Apply self.setAttribute(Qt.WA_TranslucentBackground, True) to that class

Implement the paintEvent of your mainwindow class like this (similar, might contain errors, but the principle should work):

QPixmap canvas(rect())

canvas.fill(Qt.transparent) # fill transparent (makes alpha channel available)

QPainter p(canvas)           # draw on the canvas
p.setOpacity(0.3)
p.setBrush(QBrush(Qt.white)) # use the color you like
p.setPen(QPen(Qt.transparen))

p.drawRect(rect()) # draws the canvas with desired opacity

p.start(self)      # now draw on the window itself
p.drawPixmap(rect(), canvas)
like image 101
Aaron Avatar answered Sep 19 '22 15:09

Aaron


I just wanted to provide another solution in case someone else runs into this problem. The way I solved it is like this.

First set your background to be completely transparent. This only applies to the window's background, and not the children objects.

self.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)

You can remove the border if you want with this.

self.setWindowFlags(QtCore.Qt.FramelessWindowHint)

Now, if you want there to still be some background color, apply a QFrame to your window, and place all child objects within it. Using your style sheet, set the color of the frame and your desired opacity like this. The last value is the opacity percentage.

self.main_frame.setStyleSheet("background-color: rgba(0, 120, 185, 60)")
like image 45
BobFromBilling Avatar answered Sep 16 '22 15:09

BobFromBilling