search
LoginSignup
2

More than 1 year has passed since last update.

posted at

updated at

PySide2で他のアプリにオーバーレイするアプリケーションを作る (1)

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

前置き

はい、昨日に引き続いて、
「別アプリケーションにオーバーレイさせるアプリケーション」に必要な技術を書いていきます。

そもオーバーレイするアプリをには何が必要なん?って話ですよね。

過去にもQiitaでオーバーレイフォームを作った方が記事を書いていて、そこから引用すると

方針
 オーバーレイは、以下のような特徴があります。
 それらを順番に実現します。
 ・拡大・縮小とかの枠がない
 ・タスクバーに表示されない
 ・必要なところは半透明、必要ないところは透明
 ・指定の位置にある
 ・常に画面の前面にある
 ・クリックは透過する

大体自分もこんな感じだと思ってるので、この方針を真似て作っていきます。

現状の確認

先に上がった特徴のうち、今の状況は

課題 備考
:white_check_mark: 拡大・縮小とかの枠がない WindowFlagsに「FramelessWindowHint」をセット
:white_check_mark: 必要なところは半透明、必要ないところは透明 「WA_TranslucentBackground」を有効にする
:white_check_mark: クリックは下のレイヤへ透過する 「WA_TranslucentBackground」を有効にする
「WA_TransparentForMouseEvents」を有効にする
:white_large_square: 常に画面の前面にある
:white_large_square: タスクバーに表示されない
:white_large_square: 指定の位置にある 常に対象アプリのウィンドウに追従させたい

という感じですね。


このうち、「指定の位置にある」は下調べした感じ面倒なのはわかったので、
後日に回して、本日は以下の2つを解決したいと思います。

  • 常に画面の前面にある
  • タスクバーに表示されない

常に画面の前面にある

めちゃくちゃ簡単です。
WindowFlagにWindowStaysOnTopHintをセットするだけです。


from PySide2 import QtWidgets
from PySide2 import QtCore, QtGui

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

        self.setWindowTitle("Sample")
        self.setFixedSize(480, 320)

        self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)


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

04_01.gif

できましたね!

タスクバーに表示されない

タスクバーから表示を消すのは、WindowFlagに「Tool」をセットするだけですので簡単ですね。

ただし、WindowFlagの「FramelessWindowHint」を組み合わせてしまうと、
プロセスを終了する手段がコマンドラインによるプロセスキルか、
タスクマネージャーに頼らざるを得ないため、以下の要素も必要となります。

  • タスクトレイに表示される。
  • タスクトレイからアプリケーションを終了させる。

そこで役に立つのが、「QSystemTrayIcon」です。

QSystemTrayIconはタスクトレイ内のアイコンを扱うクラスです。

余談ですが、QSystemTrayIconのshowMessageメソッドを呼び出すと、以下のようにトースト通知も出せます。
(通常のアプリケーションだとタスクトレイに登録とかしないので、あまり実用性はないですが……)

04_02.gif

アイコンにはコンテキストメニューを追加できるので、アプリケーションの終了処理を登録しておきます。
使ってみると以下のような感じです!

#!python3
# encoding:utf-8

from PySide2 import QtWidgets
from PySide2 import QtCore
from PySide2 import QtGui

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

        self.setWindowFlags(QtCore.Qt.Tool|QtCore.Qt.FramelessWindowHint|QtCore.Qt.WindowStaysOnTopHint)

        # 撮影用に位置を変更
        self.setGeometry(1400, 850, 200, 200)

        label = QtWidgets.QLabel("Frame Less Window Sample", self)
        label.setGeometry(0, 0, 200, 200)
        label.setStyleSheet("background-color: #222; color: #EEE;")

class TaskTray_Icon(QtWidgets.QSystemTrayIcon):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        menu = QtWidgets.QMenu()

        quit_action = menu.addAction("Quit")
        quit_action.triggered.connect(self.__quit)

        # コンテキストメニューに作成したメニューをセット
        self.setContextMenu(menu)

        # NOTE: アイコンには通常はpngなどを指定するが、
        # サンプルなのでPixmapでもモックを作ってお茶を濁す。
        # icon = QtGui.QIcon('icon.png')
        pixmap = QtGui.QPixmap(QtCore.QSize(32, 32))
        pixmap.fill(QtGui.QColor("red"))
        icon = QtGui.QIcon(pixmap)

        self.setIcon(icon)

    def __quit(self):
        QtWidgets.QApplication.quit()


if __name__ == "__main__":
    app = QtWidgets.QApplication()

    # トレイアイコンを生成して表示。
    trayicon = TaskTray_Icon()

    trayicon.show()

    window = Window()
    window.show()
    exit(app.exec_())

04_03.gif

締め

以上で今日の記事は終了です。
やったことを踏まえると、こんな感じですね。

課題 備考
:white_check_mark: 拡大・縮小とかの枠がない WindowFlagsに「FramelessWindowHint」をセット
:white_check_mark: 必要なところは半透明、必要ないところは透明 「WA_TranslucentBackground」を有効にする
:white_check_mark: クリックは下のレイヤへ透過する 「WA_TranslucentBackground」を有効にする
「WA_TransparentForMouseEvents」を有効にする
:white_check_mark: 常に画面の前面にある WindowFlagsに「WindowStaysOnTopHint」をセット
:white_check_mark: タスクバーに表示されない WindowFlagsに「Tool」をセット
QSystemTrayIconでタスクトレイに登録
コンテキストメニューからアプリケーションを終了
:white_large_square: 指定の位置にある 常に対象アプリのウィンドウに追従させたい

まあ、いい感じにオーバーレイウィンドウに近づいてきましたね!

評価ラベル ランク(おそらく5段階)
おすすめ度 ★★
難易度
ニッチ ★★★★
汎用性 ★★
OBSとAEとPS使って
説明用Gif作るのめんどい
ScreenToGifを使え
ScreenToGif ★★★★★★★★★★

明日は遂にWinApiとか使いだすので、よろしくお願いします。
では、また明日!

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
2