LoginSignup
31
40

More than 3 years have passed since last update.

PyInstaller+PyQtでアイコン対応

Last updated at Posted at 2018-03-13

はじめに

Pythonを使ってちょっとしたGUIアプリを作るときに,よくPyQtで書いてそれをPyInstallerでexeにパッケージングしています.
その時にお気に入りのアプリはアイコンもつけておきたいので,その方法についてまとめます.

対応したいアイコン表示は以下の二通りです.

  • エクスプローラに表示されるexeファイルのアイコン
  • タイトルバーやタスクバーに表示されるアイコン

開発環境

今回確認した環境は以下の通りです.

  • Windows10 Pro
  • Python 3.6.4
  • PyInstaller 3.3.1
  • PyQt5 5.10.1

インストール

PyInstallerとPyQtはpipからインストールができます.

> pip install pyinstaller pyqt5

exeファイルのアイコン

PyInstallerでパッケージングするときにアイコンをつけることができます.

> pyinstaller foo.py --onefile --noconsole --icon=bar.ico

--iconオプションにicoファイルを指定します.
またアイコン表示とは直接関係ありませんが,--onefileオプションでパッケージングするときに1ファイルにまとめるのと,--noconsoleオプションで起動時にコンソール画面を表示しないように指定しています.

foo.png

タイトルバーやタスクバーに表示されるアイコン

こちらはPyQtのコードで対応します.QApplicationのsetWindowIcon()に画像ファイルを渡すとタスクバーにアイコンが表示されます.

from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QWidget

app = QApplication(sys.argv)
app.setWindowIcon(QIcon('bar.ico')) # pngファイルなどでもOK
w = QWidget()
w.show()
sys.exit(app.exec())

これでPyInstallerで生成したexeファイルと同じパスにbar.icoを置いておくと,タイトルバーやタスクバーにアイコンが表示されます.
ただしこのままでは,exeファイルのほかにicoファイルも同時に配布する必要があるため,もう一工夫します.

画像ファイルの組み込み

PyInstallerでパッケージングするときに,外部ファイルを組み込むことができます.組み込むにはspecファイルに記述します.specファイルは一から記述してもいいですが,上記のようにfoo.pyファイルを指定してPyInstallerを動かしているとfoo.specファイルが生成されています.これに以下の一行を追記すると簡単です.

a = Analysis(['foo.py'],
             pathex=['C:\\work\\Python\\foo'],
             binaries=[],
             datas=[],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
+a.datas += [('bar.ico', '.\\bar.ico', 'Data')]
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='foo',
          debug=False,
          strip=False,
          upx=True,
          runtime_tmpdir=None,
          console=False , icon='bar.ico')

このspecファイルを使用してPyInstallerを実行します.

> pyinstaller foo.spec

これでbar.icoファイルが組み込まれてパッケージングされます.

組み込んだファイルの読み込み

PyInstallerでパッケージングしたexeを実行するとTempフォルダに一時ファイルが展開されます.この中に上記で組み込んだ画像ファイルも展開されているので,これを読み込みます.

展開される先のパスはsys._MEIPASSから取得ができます.以下のようなコードを書いておけば,PyInstallerを使用したときと普通にPythonで実行したときとで両対応できます.

import os
import sys

def resource_path(relative):
    if hasattr(sys, '_MEIPASS'):
        return os.path.join(sys._MEIPASS, relative)
    return path.join(path.abspath('.'), relative)

これを利用して以下のようなコードを書けば,パッケージングされたexeファイルだけでタイトルバーやタスクバーにアイコンを表示することができます.

import os
import sys

from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QWidget

def resource_path(relative):
    if hasattr(sys, '_MEIPASS'):
        return os.path.join(sys._MEIPASS, relative)
    return path.join(path.abspath('.'), relative)

def main():
    app = QApplication(sys.argv)
    app.setWindowIcon(QIcon(resource_path('bar.ico')))
    w = QWidget()
    w.show()
    sys.exit(app.exec())

if __name__ == '__main__':
    main()

foo.png

31
40
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
31
40