LoginSignup
3
0

More than 3 years have passed since last update.

PySide2で作成したウィンドウを半透過させる

Last updated at Posted at 2020-12-02

この記事はTakumi Akashiro ひとり Advent Calendar 2020の3日目になります。

前置きの前置き

はい、Advent Calendarの3日目にして、もうネタが無くなりました。
最初の方にはちょっと実用的な記事を書く意識1がありましたが
仕方ないので、ここから来週の月曜までは好き勝手調べた内容を書いてきます。
TAとかまったく関係ないです。

というわけで、3日目の記事、どうぞ!

前置き

皆さんはウィンドウの透過処理、使ったことありますか?自分は今までの仕事では一回も無いですね!
突然、ウィンドウにオーバーレイさせるアプリケーションとか作りたくなったので、ちょっと覚えていこうと思います(投げやり)

ウィンドウを半透過するには得手不得手があり、使い分けが必要だったので、
今日の記事はその辺を踏まえながら解説していきたいと思います!

本日のサンプルコード

#!python3
# encoding:utf-8

from PySide2 import QtWidgets
from PySide2 import QtCore

class Window(QtWidgets.QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.setWindowTitle("Sample")
        self.setStyleSheet("background-color:white;")
        self.setFixedSize(480, 320)

        hbox = QtWidgets.QHBoxLayout()
        vbox = QtWidgets.QVBoxLayout()
        hbox.addLayout(vbox)

        button_first = QtWidgets.QPushButton("Button: 1")
        button_first.setStyleSheet("background-color:gray; color:white;height:100%")
        vbox.addWidget(button_first)

        button_second = QtWidgets.QPushButton("Button: 2")
        button_second.setStyleSheet("background-color:darkgray; color:white;height:100%")
        vbox.addWidget(button_second)

        textedit = QtWidgets.QTextEdit("QtWidgets.QTextEdit")
        textedit.setStyleSheet("background-color:lightgray;")
        hbox.addWidget(textedit)

        self.setLayout(hbox)


if __name__ == "__main__":
    app = QtWidgets.QApplication()
    window = Window()
    window.show()
    exit(app.exec_())

image.png

はい、Qt製の何の変哲もない雑なウィンドウですね。
本日はこれを透過させてみたいと思います。

手法1 ウィンドウ背景の透明化オプションをセットする

self.setWindowFlagsに「WA_TranslucentBackground」をセットすることで1ウィンドウの背景が透過するようになります。

ただしそのままでは、「WA_TranslucentBackground」をセットした時に
追加される背景を描画しない「WA_NoSystemBackground」の影響で背景色が描画されないので、
paintEvent側で背景色を描画する必要があります。

class Window(QtWidgets.QWidget):
    def __init__(self, *args, **kwargs):
        # ~中略~
        self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
        self.setStyleSheet("background-color: rgba(255, 255, 255, 127);")

    def paintEvent(self, event):
        # NOTE: トップレベルのWidgetはWA_TranslucentBackgroundフラグが立つと、
        #       背景が描画されなくなるので、paintEvent側で描画する。
        painter = QtGui.QPainter(self)
        painter.fillRect(0, 0, self.width(), self.height(), painter.background())

image.png

メリット 特定Widgetのみを透過できる
デメリット ウィンドウのWidgetの透過には
WindowFlagsのFramelessWindowHintが必要なため、
タイトルバーが消えてしまう

手法2 ウィンドウに直接透明度を適用する

class Window(QtWidgets.QWidget):
    def __init__(self, *args, **kwargs):
        # ~中略~
        self.setWindowOpacity(0.5)
メリット めちゃくちゃ簡単に透過を実装できる
デメリット Widget個別に透過度を設定できない

image.png

締め

評価ラベル ランク(5段階)
おすすめ度
難易度
ニッチ ★★★★
汎用性
もやもや度 ★★★★

image.png

(上記は加工した画像です)

今回、実はオーバーレイの件とは別件でこういう感じをやりたくて、調べていたんですがダメでした……

一応PySide2+Qtをビルドしなおして、QtWinモジュールを追加すれば、Win7時代によくあったガラスフレームが使えるようで、
上記の画像っぽい感じになるんですが…今回はそこまでの情熱はないです……

まあ手法1に自作のタイトルバーを追加すればいいだけなんで、問題はないんですけどね!!!!(精一杯の負け惜しみ)

というわけで個人的には若干消化不良な結果になりましたが、
今日の記事はここまでで終わりです。

ではでは!


  1. そこら辺の話は土曜当たりの記事で書く予定です。 

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0