Flask + Electron で Python の GUI アプリを作成する方法

目次

概要

Flask で画面を作成して Windows で動作する GUI アプリケーションを作成する方法について解説します。

手順

前提

Node.js がインストールされていて、コンソールより npm コマンドが使えるものとします。

1. 雛形をダウンロードする

nekobean/electron-flask-template: Electron with flask example. にテンプレートがあります。

git clone https://github.com/nekobean/electron-flask-template.git

2. セットアップする

Python 環境は Pyinstaller でバイナリ化した際に PC の Python 環境に入っている使用しないライブラリもパッケージ化されてしまうことを防ぐために、venv を使用して仮想環境を作成し、そこに Flask など使用するライブラリのみを pip でインストールします。

npm install
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt

3. デバッグモードで起動する

開発中は以下のコマンドでデバッグモードで起動できます。

npm start

4. ビルドする

以下のコマンドでビルドできます。ビルドが完了すると、dist\win-unpacked 以下にパッケージが出力されます。

npm run build

仕組み

Flask の実行と終了

Flask と Electron

nodejs の child_process で、Flask を実行し、127.0.0.1:5000 にサーバー立てます。 ビルドしたパッケージでは Pyinstaller によって生成される実行ファイル build/dist-python/app.exe、デバッグ時は python コマンドで web/app.py を実行することで Flask を起動します。

const PY_EXE_FILE = path.join(__dirname, "dist-python/app.exe");
const PY_ENTRY_FILE = path.join(__dirname, "web/app.py");

const startPythonSubprocess = () => {
    if (app.isPackaged) {
        subpy = require("child_process").execFile(PY_EXE_FILE, []);
    } else {
        subpy = require("child_process").spawn("python", [PY_ENTRY_FILE]);
    }
};

execFile() で子プロセスで実行ファイルを起動した場合、親プロセスが終了しても子プロセスが残ったままになってしまうため、ウィンドウが閉じられたタイミングで ps-tree で Flask を起動しているプロセスを探して、終了します。

const killPythonSubprocesses = (main_pid) => {
    let exeFilename = app.isPackaged ? path.basename(PY_EXE_FILE) : path.basename(PY_ENTRY_FILE)

    let cleanupCompleted = false;
    require("ps-tree")(main_pid, (err, children) => {
        // Kill all child processes.
        children
            .forEach((x) => {
                if (x.COMMAND == exeFilename)
                    process.kill(x.PID);
            });

        subpy = null;
        cleanupCompleted = true;
    });

    return new Promise(function (resolve, reject) {
        (function waitForSubProcessCleanup() {
            if (cleanupCompleted) return resolve();
            setTimeout(waitForSubProcessCleanup, 30);
        })();
    });
};

app.on("window-all-closed", () => {
    // On macOS it is common for applications and their menu bar
    // to stay active until the user quits explicitly with Cmd + Q
    if (process.platform !== "darwin") {
        killPythonSubprocesses(process.pid).then(() => {
            app.quit();
        });
    }
});

このトップページをElectron で読み込んで、画面に出力しています。

mainWindow.loadURL("http://127.0.0.1:5000/");

ビルドの仕組み

  1. build_python.js を実行すると、Pyinstaller により Python コードが実行ファイルに変換され、build/dist-python/app.exe が出力されます。
  2. electron-builder により、dist\win-unpacked 以下にパッケージが出力されます。

コメント

コメントする

目次