WindowsでのPythonデスクトップアプリ開発環境構築

Windows環境でもPythonのちょっとしたプログラムを汎用化して他の人に渡せるようにしたい。しかし,これにはいくつか問題がある。ここではそれらの問題の自分なりの解決策を示していきたい。大きく以下の構成で記述していく。
Python環境の構築
Pythonプログ ラムはPythonがインストールされていないと動かないので,動作確認もできない。Python環境を構築するために,いろいろなPythonのディストリビューションがある。例えばAnacondaやEnsightなどだ。
      WindowsでのおすすめはPython(x, y)を使うことだ。
    
2016-08-10追記:この記事はもともと2014-07-24に書かれ,内容が古くなったので少し修正。
今はもうPython(x, y)はお勧めでない。なぜなら,Python(x, y)はPython2系しか使えないからだ。現在では,Python2系と3系の両方を提供しているWinPythonかAnacondaがお勧めだ。WinPythonはWindows専用で,ポータビリティに重点が置かれたディストリビューションで,USBなどにインストールしてそのまま使えるようになっている。Anacondaはクロスプラットフォームで独自のcondaというパッケージ管理システムを持っている。デスクトップでメインの開発環境として使うなら,Anacondaがよいだろう。
このインストーラーを使うことで,QtやwxPythonやpipなどたいていのPython関係のモジュールやプログラムインストールできる。おそらくこれひとつでPython環境の構築は事足りる。不足しているもの(例えばBasemap)などは追加でインストーラーからインストールするか,一緒についてきたpipでインストールすればよい。
GUI
Pythonで作ったプログラムを他の人にも使ってもらえるようにするには,GUIを搭載したものがやはりよいだろう。PythonでGUIを実現するためのライブラリはいくつかある。主要なものは以下4種類だろう。
-         PyQt(PySide)
 - wxPython
 - Tkinter
 - PyGTK
 
これら4種を主観で比較すると以下となる。
- 機能
 - PyQt>wxPython=PyGTK>Tkinter
 - ライセンス
 - Tkinter=wxPython>PyGTK=PySide>PyQt
 - 手軽さ
 - Tkinter>wxPython=PyGTK>PyQt
 
機能やコミュニティーとしては,PyQtが一番安定している。ライセンスとしては,TkinterとwxPythonがゆるく(BSD系),商用利用も問題ない。PyQtはQtをベースにしたウィジェットである。こちらはオープンソースプロジェクトならフリーに使えるが,商用だと有料となる。
どのライブラリを採用するかは用途によって変わってくる。
- PyQt
 - パフォーマンスや品質,大規模プロジェクト
 - Tkinter
 - 手軽さ
 
パフォーマンスや品質,大規模プロジェクトを念頭に置くなら,PyQt一択となるだろう。しかし,個人で既存のPythonプログラムにGUIをちょっと付け足したいくらいなら,Tkinterがよいだろう。Tkinterはtcl/tkというライブラリがベースとなっている。Python標準のライブラリとなっており,Pythonさえインストールされていれば,パッケージングしなくてもそのまま配布可能だ。PyQtやwxPythonはPython非標準ライブラリなので,配布時にはパッケージングが必須となる。また,ライブラリ自体もこれら3種の中では最も小さいので,全体的に手軽で個人でGUIを作るのに向いている。
wxPythonは,手軽さや機能がPyQtとTkinterのちょうど間の位置づけとなっている。個人的には,wxPythonやPyGTKを使うくらいならPyQtかTkinterでよいと思う。おそらく,機能性が要求されるが,ライセンス的に商用利用を視野に入れる場合や,GTK+やwxWidgetsの開発経験を活かす場合にwxPythonやPyGTKを使うことになるのだろうと思う。
私はLinuxと同じ環境で開発できることから,Windowsでは基本的にCygwinやMSYS2を使っている。CygwinだけでPythonのGUIを開発するのは非常に困難だ。CygwinでインストールするPyQtやwxPythonなどの各種のPython GUIモジュールはインストール自体が困難であり,しかもX Windows上でしか動作しない。つまり一旦Cygwinで以下のようにstartxコマンドを実行してXを起動してX Windows上でしか動作しない。
startx
    ここは妥協してGUIの 動作確認はPythonxyでインストールしたWindowsのPythonを実行することで確認することがベストだ。ソースの記述だけはCygwinか ら行い動作の確認のみ以下のようにしてWidowsのPythonで起動して確認する。
C:/Python27/python.exe GUIプログラム.py
    なお,単にファイルをダブルクリックしたり,以下のコマンドでデフォルトのプログラムで起動しても問題ない。 おそらくこちらの方が確認は楽だろう。
cygstart GUIプログラム.pyexe化
PythonでGUIやその他の便利なプログラムを作ったとしても他の人が使えるとは限らない。独自のモジュールを使っていたり,利用者にPython環境がないことも ありえるからだ。この解決策は,Pythonプログラムをバイナリ化(exe)にすることだ。こうすることでWindows環境でPythonのない環境でもPythonのデスクトップアプリを実行できる。
Pythonプログラムのexe化にはいくつか方法がある。例えば以下のプログラムを使ってパッケージ化するのが一つの方法だろう。
- py2exe
 - cx_Freeze
 
しかし,上記のプログラムを利用した場合,作成されたexeファイルとともに共有ライブラリ(.dll)ファイルが必要となる。つまり,exeファイルとdllファイルを同じディレクトリに配置しないといけない。またはPATHを通しておかないといけない。他人に渡すことを考えるとはっきりいって邪魔くさい。単一のexeファイルだけでスタンドアローンで実行するようにするのが親切だろう。多少ファイルサイズがでかくなったとしてもだ。
これを実行するよい方法がある。それはpyinstallerを使うことだ。これを使うことで驚くほど簡単に単独で動作するexeファイルを作れる。py2exeやcx_Freezeを試すのがバカらしくなってしまった。
参考
まず,前提としてWinPythonやAnacondaでPython環境をインストールしておく。
- コマンドプロンプトを開く。
 - 以下のコマンドを実行してPyInstallerをインストール
 
pip install pyinstaller
      これで準備は完了。例えばhoge.pyファイルをバイナリにするときは以下のコマンドを実行する。
pyinstaller -F --noconsole hoge.py
    なおWindowsで動作するようにしたければWindowsのPyInstallerでexe化しないといけない。Cygwinからやる場合は,例えば以下のようにしてこのときだけ先ほどインストールしたWindowsのPyInstallerを使う。
C:/Python27/Scripts/pyinstaller -F --noconsole hoge.py
    また,デメリットとしてバイナリサイズが肥大化する。例えば以下で掲載した簡単なアプリでもPyQtで16 MB,Tkinterで9 MBほどになる。これは必要なDLLやモジュールを一つのファイルにまとめたことによる弊害である。ただ,サイズの大きさよりも単独で動くものを作れるメリットのほうが大きいので,この問題には目をつぶることにする。
サンプルアプリ
以上の手順によりWindowsにおけるPythonデスクトップアプリ開発環境が整った。試しにPyQtとTkinterのサンプルアプリを起動させてみよう。
以下のコードを適当な名前で保存してバイナリ化してみよう。
PyQt4
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# hello-qt4.py
#
# Here we provide the necessary imports.
# The basic GUI widgets are located in QtGui module. 
import sys
from PyQt4.QtGui import *
# Every PyQt4 application must create an application object.
# The application object is located in the QtGui module.
a = QApplication(sys.argv)
# The QWidget widget is the base class of all user interface objects in PyQt4.
# We provide the default constructor for QWidget. The default constructor has no parent.
# A widget with no parent is called a window. 
w = QWidget()
w.resize(320, 240)  # The resize() method resizes the widget.
w.setWindowTitle("Hello, World!")  # Here we set the title for our window.
w.show()  # The show() method displays the widget on the screen.
sys.exit(a.exec_())  # Finally, we enter the mainloop of the application.
引用元:PyQt – Wikipedia
Tkinter
#!/usr/bin/env python3
# hello-tkinter.py
import tkinter as tk
class Application(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        self.pack()
        self.createWidgets()
    def createWidgets(self):
        self.hi_there = tk.Button(self)
        self.hi_there["text"] = "Hello World\n(click me)"
        self.hi_there["command"] = self.say_hi
        self.hi_there.pack(side="top")
        self.QUIT = tk.Button(self, text="QUIT", fg="red",
                                            command=root.destroy)
        self.QUIT.pack(side="bottom")
    def say_hi(self):
        print("hi there, everyone!")
root = tk.Tk()
app = Application(master=root)
app.mainloop()
      引用元:25.1. tkinter — Tcl/Tk の Python インタフェース — Python 3.5.1 ドキュメント
まとめ
WindowsでのPython開発環境の構築方法と,GUIライブラリの選定,パッケージング方法について説明し,最後にサンプルアプリのパッケージングまで紹介した。
今後はTkinterを使ったGUIアプリの開発方法を勉強していこうと思う。やはりGUIがあったほうがユーザー(未来の自分)に優しい。そして実益的だと思う。
