よちよちpython

独習 python/Qpython/Pydroid3/termux/Linux

WSLでtkinterとpyinstallerを動かすテスト

WSLでtkinterとpyinstallerを動かすテスト

注意
WindowのWSLでUbuntuを入れ、そこでPythonを動かす環境向けの投稿。

PythonGUI(グラフィカルなユーザー・インターフェース)アプリを作るライブラリは

  • Tkinter
  • Kivy
  • PyQt
  • wxPython
  • PySimpleGUI
  • Pygame

等いくつかあります。その中でもTkinterPythonに標準装備されています。

今回おこなうこと

  • TkinterがWSLのUbuntuで動くかかどうか試します。

  • Tkinterで作ったpyファイルをpyinstallerexeファイルに変換し、動作確認します。



LinuxGUIを動かすにはX Window SystemとかX serverとか呼ばれるものをインストールしなければなりません。それと、GUIのテキストボックスに日本語入力するような場合はLinuxの日本語入力設定も必要です。のちほど。



【実行環境】

  • Windows10 Home
  • WSL:Ubuntu:Anaconda
  • Python3.8



目次



先に結論を申し上げますと

  1. tkinterはWSLのUbuntuで動いた
  2. 注意)pyinstallerで作成したtkinterアプリを動かせた
  3. 注意)pyinstallerはクロスコンパイラではない


上の3つについて、

  1. WSLのLinuxに入れたAnacondaのPythontkinterアプリを作成し、WSLで実行することができたGUIが起動した)。
    自分の環境ではWindows側にPythonを入れていないので、WSLを起動させないとpyファイルは動かせない。

  2. pyinstallerpyファイルスタンドアローン型のEXE実行ファイルに変換するライブラリ」 です。結果的に 実行ファイルは動かすことが出来た。 が、条件がある。
    検索すると、stackoverflowなどのサイトでは「Wine Linuxでは実行ファイルが作れるが、Debian Linuxでは無理げ」とか、「実行ファイルには変換できたが動かない」など実行環境でマチマチのようです。
    また、「全てのpythonライブラリに対応している訳ではない」ようなことが公式ドキュメントに書いてあります。対応ライブラリを表にしてあるが、tkinterは載っていない。(DjangoやmatplotlibなどはEXEファイルに出来る。)。載ってないが今回のは動いた。

  3. 「pyinstallerはクロスコンパイラではない」ともある。Windowで作ったpyファイルはWindowで動く実行ファイルにしか変換できない、Linuxで作ったものはLinuxでしか動かない、その他のOSも同様。という意味だそうです。
    よって、WSLのLinuxOS上のpythonで作ったpyファイルをpyinstallerで実行ファイルに変換できたとしても、Windowのエクスプローラでクリックしても動かない。動かすにはLinuxから実行する以外ない。

以上。


ここから以降は、実際にtkinterでアプリ作成と実行テスト、pyinstallerでの実行ファイル作成作業に移っていきます。



UbuntuGUIを動かす + 日本語入力できるようにする

WSLでLinuxを入れたからと言って、ハードディスクをパーティションで別けてブートローダーでOSを切り替える時のように見た目がゴロッと変わるわけでもなく、普通にWindowsで、何が動いているのか分かりにくい。

VSCodeもJupyterNotebookも、巷にあふれる「WSLでPythonを動かす設定方法」に従ってインストールいれば普通に日本語入力できるし・・・GUIの設定って言うが、VSCodeもJupyterもGUIで動かしてるし・・・

何か他に設定しなくちゃいけないの?



しなくちゃいけないみたいです。
自分の環境では、X serverは設定が済んでいたのでtkinterGUIが表示されたものの、GUIのテキストボックスに日本語入力ができなかった。

とりあえず、それらの設定方法は後回しに、次へ進む。

X server の起動

windowsのスタート ⇒ VcXsrv ⇒ XLaunch(またはデスクトップ上のアイコン) をクリック。
XLaunchのダイアログが起動する ⇒ 全てデフォルトで「次」をクリック。
画面右下のタスクバーの「」のアイコンを押すと先ほどクリックしたXLaunchのアイコンが追加されているのが確認できる。(バツ印でXみたいなヤツ)

これを起動しないとtkinterGUIが表示されない。



この段階でXLaunchのアイコンがないとか、X Serverの設定が済んでいない場合は
【Windows 10】WSLでGUIアプリを動かす方法と日本語入力設定方法【VcXsrv】 - あんりふ! などを参考に。



tkinterの動作確認

さて、tkinterGUIライブラリの「Tcl/Tk」を利用している。これはtkinterと同様にPythonに最初から付属と。次のコマンドをターミナルで実行すると、「Tcl/Tk」のダイアログが起動する。

$ python -m tkinter

f:id:chayarokurokuro:20210713183413j:plain



閉じるには「QUIT」か「×」ボタン。

「Tcl/Tk」のダイアログが起動すれば、GUItkinterも利用可能な状態ということが確認できたっちゅうことで、出来なかったら前の工程に戻ってX serverの設定を確認のこと。

できたとして、次にいきます。早速GUIアプリを作成してみます。



ただダイアログが起動するだけのアプリ作成

pyファイルを作って、そのあとファイルをコマンド実行します。
(↓はJupyterのマジックコマンドの%%writefileでファイル作成しております)

%%writefile hello_tk.py
import tkinter as tk

# ウィンドウを作成
win = tk.Tk()
win.title("こんにちは、世界!")
win.geometry('400x300') # 400x300 のxは小文字のエックス

# ウィンドウを動かす
win.mainloop()
Overwriting hello_tk.py
$ python hello_tk.py

f:id:chayarokurokuro:20210713183441j:plain


タイトルしかないウィンドウが起動した。



テキストボックス アプリ作成

テキスト入力に応じて何か返すアプリを作る。

%%writefile tkinter_gui.py
import tkinter as tk
from tkinter import messagebox as mbox

# ウィンドウを作成
win = tk.Tk()
win.geometry('500x250')

# 部品を作成
# ラベルを作成
label = tk.Label(win, text="お名前は?")
label.pack()

# テキストボックスを作成
text = tk.Entry(win)
text.pack()
text.insert(tk.END, 'なにがし')

# OKボタンを押したとき
def ok_click():
    # テキストボックスの内容を得る
    s = text.get()
    # ダイアログを表示
    mbox.showinfo('挨拶', s + 'さん、こんにちは!')
    
# ボタンを作成
okButton = tk.Button(win, text='OK', command=ok_click)
okButton.pack()

# ウィンドウを動かす
win.mainloop()
Overwriting tkinter_gui.py
$ python tkinter_gui.py

f:id:chayarokurokuro:20210713183523j:plain



日本語入力できない・・ので設定

上のテキストボックスに日本語入力ができなかった
Linuxの日本語入力設定をしていないから。mozcとか入力メソッドを入れなきゃならんようです。

参考リンク(上に貼り付けたのと同じ)
【Windows 10】WSLでGUIアプリを動かす方法と日本語入力設定方法【VcXsrv】 - あんりふ! などを参考に行いました。

設定後、fcitx-mozcでの入力切替をできるようにするためにはターミナルで

$ fcitx-autostart    # ← コマンド
Fcitx is running correctly.   # ← 出力

とコマンドする。

tkinterで出たGUIに日本語入力する場合は、「Ctrl+Space」を押すと入力メソッドが「Mozc」に変わる。
戻す時は再び「Ctrl+Space」(アルファベットしか入力できなくなる)。

fcitx-mozcの入力設定を行うには

$ fcitx-config-gtk3

をコマンドする。GUIのダイアログが起動し設定できる。
だが、「入力メソッド」で追加ボタン「+」を押してもmozcも何も候補が出てこない・・・。

設定後に実行。

f:id:chayarokurokuro:20210713183643j:plain



とりあえず日本語入力できたのでfcitx-mozcの設定云々は放置する。



tkinterで使えるフォントを確認する

%%writefile tkinter_font_families.py
import tkinter as tk
import tkinter.font

win = tk.Tk()
print(tkinter.font.families())
Writing tkinter_font_families.py
# (Jupyterで確認しています)
!python tkinter_font_families.py
('estrangelo midyat', 'clearlyu devangari extra', 'utopia', 'clearlyu arabic', 'luxi serif', 'cursor', 'clearlyu arabic extra', 'fixed', 'estrangelo nisibin', 'lucidatypewriter', 'courier 10 pitch', 'open look glyph', 'estrangelo talada', 'serto urhoy', 'bitstream charter', 'terminus', 'clearlyu pua', 'serto mardin', 'estrangelo edessa', 'clean', 'terminal', 'serto jerusalem', 'gothic', 'new century schoolbook', 'luxi sans', 'bitstream vera sans mono', 'clearlyu alternate glyphs', 'lucidabright', 'bitstream vera serif', 'estrangelo antioch', 'song ti', 'estrangelo quenneshrin', 'open look cursor', 'serto malankara', 'helvetica', 'mincho', 'estrangelo nisibin outline', 'clearlyu', 'east syriac adiabene', 'serto batnan', 'courier', 'lucida', 'clearlyu devanagari', 'nil', 'goha tibeb zemen', 'serto kharput', 'estrangelo turabdin', 'fangsong ti', 'charter', 'times', 'luxi mono', 'newspaper', 'serto jerusalem outline', 'clearlyu ligature', 'east syriac ctesiphon', 'proof', 'symbol', 'bitstream vera sans')



ここからはpyファイルをexeファイルに変換する作業に移ります。

pyinstallerで py ⇒ exe

pyファイルをスタンドアローンな実行ファイル(EXEファイル)にする為のライブラリをインストールします。
これを使うことにより、PythonがインストールされていないPCでもexeファイルを実行できるようになる。
WSLでLinuxを起動しなくとも、Pythonで作ったプログラムが動かせるようになるはず!



pyinstallerのインストール

インストールします。

  • pipの場合は
$ pip install pyinstaller



  • condaの場合は
$ conda install -c conda-forge pyinstaller  

以下、出力

Collecting package metadata (current_repodata.json): done
Solving environment: done

## Package Plan ##

  environment location: /home/user/anaconda3

  added / updated specs:
    - pyinstaller


The following packages will be downloaded:

    package                    |            build
    ---------------------------|-----------------
    altgraph-0.17              |     pyhd8ed1ab_0          21 KB  conda-forge
    macholib-1.14              |     pyh9f0ad1d_1          34 KB  conda-forge
    pyinstaller-4.3            |   py38ha8cb210_0         1.5 MB  conda-forge
    pyinstaller-hooks-contrib-2021.2|     pyhd8ed1ab_0          73 KB  conda-forge
    ------------------------------------------------------------
                                           Total:         1.6 MB

この4つをインストールするがよかですか?「y/n」みたいなことを聞かれたので「y」でよかですEnterした。



pyinstallerコマンドで py ⇒ exe

exeファイル化したいpyファイルを用意します。先ほど作ったテキストボックス付きの「tkinter_gui.py」というファイルをexeファイルにしてみます。

%ls | grep  tkinter_gui.py
tkinter_gui.py*

pyファイルはカレントディレクトリにある。OK。

# pyinstallerでpyファイルを一つのexeファイルに変換する
!pyinstaller tkinter_gui.py --onefile

以下、出力

14272 INFO: PyInstaller: 4.3
14273 INFO: Python: 3.8.10 (conda)
14386 INFO: Platform: Linux-4.4.0-19041-Microsoft-x86_64-with-glibc2.17
(中略)
100555 INFO: Building EXE from EXE-00.toc completed successfully.

どうやら成功した模様。2分ほどかかった。

%ls
Untitled.ipynb*  build/  hello_tk.py*               tkinter_gui.py*
__pycache__/     dist/   tkinter_font_families.py*  tkinter_gui.spec*

build/dist/の2つのフォルダ、そしてtkinter_gui.spec*が新規作成された。

再び、

$ pyinstaller tkinter_gui.spec*

をするとexeファイルが出来るようだ。

$ pyinstaller tkinter_gui.spec

以下、出力

2553 INFO: PyInstaller: 4.3
2553 INFO: Python: 3.8.10 (conda)
2620 INFO: Platform: Linux-4.4.0-19041-Microsoft-x86_64-with-glibc2.17
(中略)
66269 INFO: Building EXE from EXE-00.toc completed successfully.

どうやら出来上がった。
出来たexeファイルはdist/の中に入っているとか。

%ls ./dist
tkinter_gui*

拡張子がない。

出来た実行ファイルを動かすには

ここまで、WSLのUbuntu上に入れたAnacondaで作成したpyファイルを、pyinstallerで実行形式のバイナリファイルに変換した。実行ファイルは作業ディレクトリ内に自動作成されたdist/ディレクトリへ保存された。

で、これをWindowsで動かそうとするのだが、一番最初に書いた結論の通り、「pyinstallerはクロスコンパイラではない」ので、作ったOSと同じOS上でのみ動く実行ファイルしか出来上がらない。


では、実行失敗を見ていきましょう。

pyinstallerはクロスコンパイラではないのでWindowsでは動かない

Windowsエクスプローラからこのファイルをクリックしても「このファイルを開く方法を選んで下さい。」とダイアログが出る。

名前をtkinter_guitkinter_gui.exe に変えればよいのかな?

# ファイル名を変更
mv ./dist/tkinter_gui ./dist/tkinter_gui.exe



変えた。再びWindowのエクスプローラからファイルをクリックで実行する。

f:id:chayarokurokuro:20210713183837j:plain



動かない。ネット検索して調べると

pyinstallerはクロスコンパイラではない為、Windows用ならWindowsで、Linux用ならLinuxで作成する必要がある云々

結局、WindowsPCで作ったのだがWSLのUbuntuLinuxで作ったので、実行ファイルはLinuxで動くものしか出来ない。Linuxといっても別のディストリビューションLinuxでこのファイルが動くかは試してないので不明。

WSLのUbuntuからなら動く

ならば、wsl起動中のターミナルで実行すれば動くだろう!
動いてもらわねば困る。

$ ./dist/tkinter_gui.exe

f:id:chayarokurokuro:20210713183908j:plain


よっしゃー!動いた!

拡張子を外して元の名前に戻します。

$ mv ./dist/tkinter_gui.exe  ./dist/tkinter_gui
$ ./dist/tkinter_gui

ファイル名を変えただけなので、当然動く。



ターミナルで実行してみる。

# ディレクトリ構成 (ディレクトリのみ表示
!tree -d
.
├── __pycache__
├── build
│   └── tkinter_gui
└── dist

4 directories
# ディレクトリ構成 (実行ファイルの入ったdist/内のみ表示
!tree dist/
dist/
└── tkinter_gui

0 directories, 1 file

ターミナルで実行ファイルを実行。

((base) 茶屋六郎九郎:@tkinter_sample$ ./dist/tkinter_gui

※(tkinter_sampleという名前のディレクトリから実行しています)

これも動く。



おわりに

今回の場合は、他のLinuxユーザーへの配布を目的としなければ、わざわざpyファイルを実行ファイル化する意味はない。自分で使う分に関しては、そのままpyファイルを実行すればよいので。

WSLのUbuntutkinterが動くことと、pyinstallerがクロスコンパイラではないことが分かった、というのが今回の収穫でございました。



以上です。