search
LoginSignup
0

More than 1 year has passed since last update.

posted at

updated at

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

この記事は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. そこら辺の話は土曜当たりの記事で書く予定です。 

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
What you can do with signing up
0