Nimを使ってデスクトップアプリケーションの作成にチャレンジします!!!
Win32APIも使えるのでそれで1から素組という技もありますが、さすがにそれではきつい💦
なので、良いライブラリがないか探したところ、NiGuiというライブラリが良さげなので、そちらを使って開発していきます。
(nimxというのも試したのですが、こちらは起動時にWARNINGが出るなどいまいちだったので、こちらにしました)
Nimの環境設定に関しては、前の記事 プログラミング言語[Nim]を始めてみた を参照してみてください。
コンソールを起動して以下のコマンドを入力
nimble install nigui
以上です。
基本的なWindowを表示するプログラムを作成します。
フォルダ D:\Projects\nim\nimtest02 を作成した後、VSCodeを起動フォルダを開きます
VSCodeからフォルダを開き、メニューより ターミナル → タスクの構成... を選択すると、
tasks.json ファイルが開くので、以下を入力します。
前回のHelloWordプログラムとの違いは、commandに --app:gui --threads:on を追加している点になります。
メニューより 実行 → 構成の編集 を選択する。
launch.json ファイルが開くので、以下を入力
こちらの変更点は、programの名称のみで、他に違いはないです。
ただ空のWindowを表示するだけのプログラムを作成してみます。
Ctrl+Shift+B でコンパイル。
F5で実行
次にアプリケーションのアイコンやファイル情報をリソースファイルを用いて埋め込みます。
リソースは ResEdit などのリソースファイル編集ツールを使用して作成します。
アイコンは ICON HOI HOIさんのサイトから拝借させて頂いた.PNGファイルを、マルチアイコン作成を使用して.ICOファイル化し、icon.ico のファイル名で保存しておきました。
マニュフェストも作成しておきます。
app.manifest ファイルに以下を記載して保存しておきます。
コンソールより次のコマンドを入力して、nimtest02.res を作成します。
windres --input-format=rc --output-format=coff -o nimtest02.res nimtest02.rc
作成したリソースファイルをリンク時に取り込むように、tasks.json を修正します。
6行目に "--passL:nimtest02.res" を追加しています。
これでコンパイルを行うとアイコンとファイル情報が設定されているかと思います。
ただし、これだとマニュフェストがうまく反映されていないようです。
(高解像度の端末で起動するとわかるのですが、dpiAware の設定が反映されていないようです)
いろいろ調べたら、NiGUI自体も、[ユーザフォルダ]\.nimble\pkgs\nigui-0.2.4\nigui\private\windows\manifest_x64.res にマニュフェストを組み込んだリソースファイルを持っていて、そちらの内容が優先されてしまっているようです。
どうにか回避方法は無いのか考えたのですが、本当はやりたくないけど、NiGuiのソースをいじってこちらのリソースの取り込みを無効化するしか無いようです(他に良い回避方法を知っている方教えて下さい)。
リソースは、[ユーザフォルダ]\.nimble\pkgs\nigui-0.2.4\nigui\private\windows\platform_impl.nim で取り込んでいますので、そちらを修正します。
上記ソースの14~17行目をコメントアウトすることで、マニュフェストの設定内容が反映されるようになりました。
ウインドウのアイコンを先程リソースに組み込んだものにしてみます。
NiGuiの場合、Win.iconPath = [ファイル名] のように書けば、アイコンを設定できるようなのですが、それだと実行ファイルとは別にアイコンファイルを常に用意して置かなくてはならないので、先程作成したリソースの中に埋め込んだアイコンを使用できるようにします。
自分が調べた限りでは、NiGuiの機能ではiconPath以外で、ウインドウのアイコンを設定する方法はなさそう。
なので、Win32APIを使用して設定するしかなさそうです。
マルチプラットフォームではなくなってしまいますが、他のプラットフォームへの対応は今後やりたいとは考えてはいますが、その時に考える事に。
ここでまた問題が発生しました。
Win32APIを使用してウインドウを操作する場合ウインドウハンドル(HWnd)が必要になりますが、NiGUIのnewWindowで作成したウインドウの場合、HWndを取得できません(私の理解が足りないだけかもしれませんが、もし間違っていたら教えてください)。
ソースをちらっと読んだら、WindowImplクラスに一応fHandleって名前でハンドルを保存しているみたいなのですが、Privateなんですよね。。。
なので、仕方ないので再び最終手段。
本当の本当にやりたくないけど、NiGuiのソースをいじって、fHandleをPublicに変更します。
修正するのは、[ユーザフォルダ]\.nimble\pkgs\nigui-x.x.4\nigui\private\windows\platform_types1.nim になります。
修正したのは上記ソースの9,14行目に"*"を追加したところです。
非常に汚いやり方ですが、これでとりあえず自分のソースからfHandleを呼べるようになります。
次にコントロールを配置してみます。
色々といじりながら適当に配置してみます。
起動してみたのがこんな感じです。
なるほど~ .NetのWPFで言うところのスタックパネルのみでレイアウトを構成していくようなイメージですね。
DockやGrid的なものがあった方が嬉しいけど、これはこれでアリかと思います。
不満を言うと、標準で用意されているヴィジェット(コントロール)が少ないです。かなり少ないと思います。
タブとかスライダーとかイメージリストなんかも普通に用意してほしいところです。この辺りは今後増えていくような事がどっかに書いてあったので期待です。
あとはあまり細かい制御は出来ないよう。
色々凝りだすとやっぱりWin32APIを叩くことになるんですかね?
今回基本的な部分をいじってみたりして、非常に使いやすいものだという事は分かりました。
ただやはり初期バージョン故か、色々と細かい部分で残念なところもありましたです(自分が理解していないだけなのかもしれないが)。
自分がWindows以外はほとんど知らないので、Windows特有の話が多いです。
クロスプラットフォームライブラリとしては対応し難いのかもしれないが、今後に期待したいところではあります。
なにはともあれ今後も色々と調べていこうと思います。
今回は以上となります。