【目的】
tkinterで作ったアプリをexeにして配布したい
→どうせならデフォルトのアイコンではなく、好きなアイコンを設定してみたい
【環境】
Windows11
Python 3.12.8
目次
1. 動くものを作る
2. Pyinstallerでexeにする
3. exeにアイコンをつける
4. tkinter GUIにアイコンをつける
5. GUIにアイコンを付けたままexeにする
6. 簡単に解説
7. ソース
1. 動くものを作る
好きなものを作る。
簡単にカウンターアプリでも。
import tkinter as tk
def CountDown():
count["text"] = count["text"] - 1
def CountUp():
count["text"] = count["text"] + 1
root = tk.Tk()
root.title("Counter")
root.geometry("220x100")
count = tk.Label(root, text=0, font=("normal", 20))
count.pack()
tk.Button(root, text=("+"), font=("normal", 20), command=CountUp).pack(
side=tk.LEFT, padx=20, pady=5
)
tk.Button(root, text=("ー"), font=("normal", 20), command=CountDown).pack(
side=tk.RIGHT, padx=20, pady=5
)
root.mainloop()
この段階でpython main.py
とすると、tkinterのGUIアイコンはデフォルトの羽マークになる。
2. Pyinstallerでexeにする
以下のコマンドでexeファイルを作成できる。
pyinstaller main.py --onefile --noconsole
exeファイル一つだけで動くようにしたいので
--onefile
:ファイルを一つにまとめる
--noconsole
:コンソールを出さない
のオプションを指定する
上記コマンドにて作成したexeはデフォルトアイコンになる
作成したexeを実行するとタスクバーは羽マークが表示される
tkinterのGUIアイコンはデフォルトの羽マークのまま変わらない
現時点でのspecファイルはこんな感じ
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['main.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='main',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
specファイルが既にある場合、
pyinstaller main.spec
で前回に叩いたコマンドと同じ内容でexeを再生成することができる。
specファイルのあれこれについては別途記事として後日記載予定
3. exeにアイコンをつける
exeのアイコンを任意の画像にするために、コマンドの場合--icon=[ファイルパス]
オプションを使用してアイコンを指定する
pyinstaller main.py --onefile --noconsole --icon=icon.ico
上記コマンドを実行時、specファイルは以下になる。
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['main.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='main',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=['icon.ico'],
)
exe = EXE()
の末尾にiconが指定される。
specファイルを変更してpyinstaller main.spec
を実行してもいい。
作成されたexeアイコンは指定した画像になる
←before after→
※実行時のタスクバーのアイコンは変わらない
4. tkinter GUIにアイコンをつける
root.iconbitmap(default="icon.ico")
でtkinterのGUIにアイコンをつける
アイコンファイルは拡張子を.ico
にしただけだと表示されないのでしっかりとコンバートする必要がある
import tkinter as tk
def CountDown():
count["text"] = count["text"] - 1
def CountUp():
count["text"] = count["text"] + 1
root = tk.Tk()
root.title("Counter")
root.geometry("220x100")
root.iconbitmap(default="icon.ico")
count = tk.Label(root, text=0, font=("normal", 20))
count.pack()
tk.Button(root, text=("+"), font=("normal", 20), command=CountUp).pack(
side=tk.LEFT, padx=20, pady=5
)
tk.Button(root, text=("ー"), font=("normal", 20), command=CountDown).pack(
side=tk.RIGHT, padx=20, pady=5
)
root.mainloop()
5. GUIにアイコンを付けたままexeにする
この状態でpyinstaller main.spec
を叩いて生成したexeを実行すると、エラーになる
今のspecファイルではアイコンファイルを取り込んでおらず、また取り込んだとしてもexe実行時はファイルパスが変わるため、このままでは表示できない。
そのためにまずexeからも参照できるようにコードを変更する
import os
import sys
import tkinter as tk
def CountDown():
count["text"] = count["text"] - 1
def CountUp():
count["text"] = count["text"] + 1
root = tk.Tk()
root.title("Counter")
root.geometry("220x100")
iconfile = "icon.ico"
if getattr(sys, "frozen", False):
iconfile = os.path.join(sys._MEIPASS, iconfile)
root.iconbitmap(default=iconfile)
count = tk.Label(root, text=0, font=("normal", 20))
count.pack()
tk.Button(root, text=("+"), font=("normal", 20), command=CountUp).pack(
side=tk.LEFT, padx=20, pady=5
)
tk.Button(root, text=("ー"), font=("normal", 20), command=CountDown).pack(
side=tk.RIGHT, padx=20, pady=5
)
root.mainloop()
main.pyの変更後、
pyinstaller main.py --onefile --noconsole --icon=icon.ico --add-data="icon.ico;."
もしくはspecファイルを以下に変更してpyinstaller main.spec
を実行する
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['main.py'],
pathex=[],
binaries=[],
datas=[('icon.ico', '.')],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='main',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=['icon.ico'],
)
この時、
・exeのアイコン
・exe実行時のタスクバーのアイコン
・exe実行時のGUIアイコン
が全て任意指定したアイコン画像になる
完成!
6. 簡単に解説
- pyinstaller
--add-data
、datas=[('icon.ico', '.')]
にて、icon.ico
というファイルをパス.
に取り込むという処理をしている - main.py
以下の部分にて、ファイル呼び出し時にexeからだと以下のIF文がTrueになるため、exe内に取り込んだ画像を呼びだすようにしているmain.pyiconfile = "icon.ico" if getattr(sys, "frozen", False): iconfile = os.path.join(sys._MEIPASS, iconfile) root.iconbitmap(default=iconfile)
これら2つの処理によって、exe実行時もmain.py実行時もアイコンがしっかりと表示されるようになる
7. ソース
最終状態のものをアップしておきます。
参考になれば幸いです。