Electron

[Electron] Sqlite3を使う。の最期に書いたようにwindows-build-toolsがインストールできない。(2018年6月現在)
インストール方法がわかったんで書いておく。

ここにあるようにBuildTolls_Full.exeがインストール完了しているのに終わらないのとログファイルに終了したことが出力されないで、ずーっと待ち状態になっているようだ。

BuildTolls_Full.exeを終了して、ごにょごにょするといいみたいだ。

方法

---------- Visual Studio Build Tools ----------
[1918:0CCC][2018-05-30T17:47:07]i371: Updating session, registration key: SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{a9528995-e130-4501-ae19-bbfaddb779cc}, resume: ARP, restart initiated: No, disable resume: No
[0338:0FB8][2018-05-30T17:47:07]i399: Apply complete, result: 0x0, restart: None, ba requested restart:  No

------------------- Python --------------------
Python 2.7.15 is already installed, not installing again.

画面にこれが出たら、

  1. BuildTolls_Full.exeをタスクマネージャで終了する。
  2. C:\Users\<User Name>\.windows-build-tools\build-tools-log.txtをテキストエディタで開いて、Variable: IsInstalled = 1を追加する。
  3. しばらくすると、npmが終了する。

そのうちバージョンアップで直るでしょうね。




楽天Kobo


このエントリーをはてなブックマークに追加 Clip to Evernote
ブログランキング・にほんブログ村へ
にほんブログ村

[Electron] Hello World的なもの(3) パッケージングで作ったプロジェクトをベースにSqlite3を使うプロジェクトを作ってみる。

Sqlite3をインストールする。

npm install sqlite3 -S
npm install @types/sqlite3 -D

electron-rebuildをインストールする。

npm install electron-rebuild -D

electron-rebuildはネイティブコードを含むモジュールをElectronで使えるようにリビルドするツールだ。
インストール後、electron-rebuildを実行してリビルドする。

npx electron-rebuild -f

sqlite3を含めないようにwebpackの設定を変更する。次のようにexternalsを追加する。

  externals: {
    sqlite3: "commonjs sqlite3"
  }

これでとりあえず準備完了。

レンダラープロセスでsqlite3を使う。ここはアップロードしたソースを参照してくれ。

これで、

npm run build

でビルドして、

npm run start

で実行できる。

元のプロジェクトでは、ビルド後、実行するのに必要なファイルをdistフォルダに作られるようにしたが、sqlite3のモジュールがdistフォルダには用意されていないので、パッケージングするには、distフォルダにsqlite3のモジュールをインストールする必要がある。

src/package.jsonのdependenciesのsqlite3を追加する。
ビルド後、distフォルダでnpm installを実行してプロジェクトのフォルダでnpx electron-rebuild -f -m dist/を実行してモジュールをリビルする。

これでelectron-packagerでパッケージングする準備ができたので、electron-packagerでパッケージングする。

変更したソースをダウンロードできるようにしといた。

と、書いたところで、WindowsとLinuxも試しとかんと、と思いためてしてみると・・・
Windowsでうまいこといかん!
Windowsの場合は、管理者として実行したコマンドプロンプトでnpm install --global --production windows-build-toolsを実行し、windows-build-toolsをインストールすればいいらしいんだけど、うちのWindowsでは途中で止まっていつまでたっても(一晩待った)終わらなかった。そのうち調べて解決しないと・・・

あと、Windowsの場合って書いたけど、macOS、Linuxの場合もCコンパイラやPythonなんかが必要なんでインストールする必要がある。Pythonは標準で入ってそうだけど。




楽天Kobo


メニューを変更してみる。

アップしたソースからメインプロセスのソースを一部あげる。

const template:any = [
    {
        label:"テスト",
        submenu:[
            { label:"テスト1", click:()=> {
                dialog.showMessageBox({message:"テスト1クリック!"});
            }},
            {
                label:"サブメニュー",
                submenu:[
                    {
                        label:"テスト2",
                        click:()=>{
                            dialog.showMessageBox({message:"テスト2クリック!"});
                        },
                        accelerator:"CmdOrCtrl+Shift+G"
                    },
                ]
            }
        ]
    },
    {
        label: "編集",
        submenu: [
            {role: "undo", label:"元に戻す"},
            {role: "redo", label:"やり直し"},
            {type: "separator"},
            {role: "cut", label:"切り取り"},
            {role: "copy", label:"コピー"},
            {role: "paste", label:"貼り付け"},
            {role: "pasteandmatchstyle", label:"ペースしてスタイルを合わせる"},
            {role: "delete", label:"削除"},
            {role: "selectall", label:"すべて選択"}
        ]
    },

    <<省略>>
}

// ウィンドウの作成準備ができたときの処理を追加
app.on("ready", ()=>{
    // メニューを設定する
    const menu = Menu.buildFromTemplate(template)
    Menu.setApplicationMenu(menu)

    createWindow();
});

メニューのテンプレートを用意する。
配列でトップメニュー(と言うのかな?)のオブジェクトを用意する。これが、Windowsだとウインドウ上部に表示されるメニューになる。
002

それぞれのオブジェクト内にsubmenuでさらにメニューのオブジェクトを用意するとメニューをクリックした時に出てくるメニューになる。

メニューオブジェクトのプロパティやメソッドは、ここに詳しく書かれている。ここでは最低限必要そうなのを書いておく。

  • label:メニューの表示名
  • click:クリックした時に呼ばれるメソッド
  • accelerator:ショートカットキーの定義
  • submenu:サブメニュー
  • type:メニューのタイプ。"separator"、"checkbox"とか。
  • role:メニューの動作を定義。標準的なメニュー項目と動作が用意されているのでそれを指定する。どんなのがあるかは、ここに書いてある。clickメソッドが定義されている場合は無視される。

appのreadyイベントでMenu.buildFromTemplateを使ってテンプレートからメニューを作って、Menu.setApplicationMenuでメニューを設定する。

ポップアップメニュー

レンダラープロセスでメニューを用意しておいて、contextmenuイベントで表示する。レンダラープロセスのソースを次に示しておく。

import * as React from "react";
import {remote} from "electron";
import * as fs from "fs";
import * as electron from "electron";

const dialog = remote.dialog;
const Menu = remote.Menu;
const MenuItem = remote.MenuItem;

interface AppState {
    text?:string;
}

export class App extends React.Component<{}, AppState>  {
    private contextMenu:electron.Menu;

    constructor(props:any) {
        super(props);
        this.state = {
            text:""
        };

        // コンテキストメニューの準備(1)
        this.contextMenu = new Menu();
        this.contextMenu.append(new MenuItem({label:"テスト1", click:()=>{dialog.showMessageBox({message:"コンテキストメニュー:テスト1クリック"})}}));
        this.contextMenu.append(new MenuItem({label:"テスト2", click:()=>{dialog.showMessageBox({message:"コンテキストメニュー:テスト2クリック"})}}));

        this.onContextMenu = this.onContextMenu.bind(this);
    }

    render() {
        return <div>
                <span>Hello World</span>
            </div>;
    }

    onContextMenu(e:PointerEvent) {
        e.preventDefault();
        // ポップアップメニューを出す(2)
        ///// ↓ Electron 2.0.0でインターフェースが変わった。
        this.contextMenu.popup({window:remote.getCurrentWindow()});
    }

    componentDidMount() {
        document.addEventListener("contextmenu", this.onContextMenu);
    }

    componentWillUnmount() {
        document.removeEventListener("contextmenu", this.onContextMenu);
    }
}

ソースの(1)の部分でポップアップメニューを用意して、(2)の部分でポップアップメニューを表示している。



[Electron] ファイルオープンダイアログとファイル読み込みに保存ボタンを追加して、ファイル保存ダイアログの表示とファイル保存処理を追加した。

まるっと、新しいソースもアップしておく。

保存ボタンを押した時の処理をあげておく。

        // ファイル保存ダイアログを表示する
        dialog.showSaveDialog(remote.getCurrentWindow(), {
            filters:[
                { name: "Text File", extensions:["txt"]},
                { name: "All Files", extensions: ["*"]}
            ]}, filename=>{
                if(filename) {
                    // ファイルに保存
                    fs.writeFile(filename, this.state.text, err=>{
                        if(err) {
                            alert(err);
                        }
                    });
                }
            });

dialog.showSaveDialogでファイル保存ダイアログを表示する。

第1引数は、親ウインドウでremote.getCurrentWindow()でレンダラープロセスで表示しているページのウインドウが取得できる。

第2引数は、ダイアログのオプションを指定する。
よく使いそうなのをピックアップして書いとく。詳細はドキュメントを見よ!

  • filters:表示するや選択できるファイルの種類を配列で指定する。
filters:[
    { name: "Text File", extensions:["txt"]},
    { name: "All Files", extensions: ["*"]}
],

第3引数は、コールバック関数。
入力したファイル名(フルパス)が渡される関数を指定する。
上に載せたソースでは、Node.jsのfs.writeFileを使ってTextAreaの内容を保存している。


まるっと、ソースをアップしておく。

ここにアップしたソースから、レンダラープロセスの頭の方に追加するのと、開くボタンをクリックした時の処理をあげとく。

import {remote} from "electron";
import * as fs from "fs";


const dialog = remote.dialog;
// ファイルオープンダイアログを表示する
dialog.showOpenDialog(remote.getCurrentWindow(), {
    filters:[
        { name: "Text File", extensions:["txt"]},
        { name: "All Files", extensions: ["*"]}
    ],
    properties: ["openFile"]
}, filePaths=>{
    if(filePaths.length != 0) {
        // ファイル読み込み
        fs.readFile(filePaths[0], { encoding:"utf-8"}, (err, data)=>{
            if(err) {
                alert(err);
            } else {
                this.setState({text:data});
            }
        });
    }
});

まず、import部分の説明。

dialogはメインプロセスでしか使えないのでremoteをインポートしてる。Electronでは、Node.jsのAPIが使用できるので、ファイルを読み込むためにfsをインポートしている。

クリックした時の処理。

dialog.showOpenDialogでファイルオープンダイアログを表示する。

第1引数は、親ウインドウを指定する。remote.getCurrentWindow()でレンダラープロセスで表示しているページのウインドウが取得できる。

第2引数は、ダイアログのオプションを指定する。
よく使いそうなのをピックアップして書いとく。詳細はドキュメントを見ればいいじゃんw

  • defaultPath:デフォルトのディレクトリ
  • filters:表示するや選択できるファイルの種類を配列で指定する。
filters:[
    { name: "Text File", extensions:["txt"]},
    { name: "All Files", extensions: ["*"]}
],
  • proprties:配列で使用する機能を指定する。
    • openFile:ファイル選択を可能にする。
    • openDirectory:ディレクトリ選択を可能にする。
      macOSの場合、openFile、openDirectoryの両方を指定すると、ファイルまたはディレクトリを選択できる。Windows、Linuxの場合はディレクトリのみ選択できる。
    • multiSelections:複数選択を可能にする。

第3引数は、コールバック関数。
選択したファイル名(フルパス)の配列が渡される関数を指定する。
上に載せたソースでは、Node.jsのfs.readFileを使って読み込んで最終的にTextAreaに設定している。(TextAreaに設定するあたりはRectを使っている)


↑このページのトップヘ