Zig言語:GUI: Zig言語でDear ImGui/ImPlotを使ってみたメモ 2024/07
はじまり
Zig-0.12.0が自分の環境で珍しくまともに動いたのを機にGUIアプリが作れる
軽量 Dear ImGuiライブリ(以下ImGuiと記す)をZig言語から呼び出して使ってみました
ついでにグラフ表示ライブラリのImPlotも使ってみたメモ
ちなみにZig言語は発見して以来2.5年ぶりに触ってみることになりました 😃
- 補足
ここにはその他のZig + ImGui
プロジェクトをメモしておきます- ZGui ImPlot, ImNodesあり
- zig-gamedev ライブラリが豊富で良さそう (未使用)
- zig-sdl-imgui-poc ImGui + SDL2
- cimgui.zig GLFW + Vulkan
- https://github.com/pdoane/zig-imgui
- https://github.com/SpexGuy/Zig-ImGui/tree/master/zig-imgui
動作環境・必要条件
- WindowsOS (Window10以降)
- Linuxに対応しました (2024.10) Ubuntu/Debianファミリなら多分OK [1]
- MSys2/MinGW の基本コマンド (make, rm, cp, strip ...)を使っています [2]
- Gitコマンド
Zig言語の注意点 現時点(2024/08 - 2025/04)
Zig言語は現在も[3] 😃 開発中につき言語仕様がリリース毎に変更されて(数ヶ月から半年周期くらいか)
ユーザー側のソースコードとの互換がなくなります
従ってこのページの内容を試す場合、Zig言語のバージョンは以下を使うことを強く推奨します
具体的にはこれ
[x] zig-0.14.0 Windows OS
[x] zig-0.14.0 Linux OS
Dear ImGuiライブラリの使用
C++言語で書かれたDear ImGuiライブラリをZig言語から直接呼ぶことはできないので
C言語のヘッダファイルを持つCImGui(/CImPlot)ライブラリを経由して
Zig言語から呼び出して使います
-
Dear ImGui
C++言語で書かれたイミディエートモード [4]で動作する軽量GUIライブラリ- CImGui: Dear ImGuiを各種言語から使える様にするC言語ライブラリ
-
ImPlot
C++言語で書かれたDear ImGuiのアドオン・グラフ描画ライブラリ- CImPlot: ImPlotを各種言語から使える様にするC言語ライブラリ
-
ImNodes/CImNodes, ImGuizmo/CImGuizmo, etc
今回未使用の他のアドオンライブラリ -
本当はラッパーライブラリが...
例えばCImGuiライブラリ
とユーザーGUIプログラム
の間に
*.jsonファイルからZig言語で書かれた関数変換ッパーライブラリ
(後述)を生成し
ユーザー側はそのライブラリ関数経由でを使うのが将来の姿
今回はCImPlot用の関数変換ラッパーライブラリ
(後述)のみを作りました
Zig言語のメリットの一つにC言語ライブラリを直接呼べるというのがあって
今回はそれを使ってみました[5]
Dear ImGuiのバージョン
ImGui/CimGui version 1.91.8dock (2025/08) (最新バージョンはここ)
GUIライブラリ使用時のポイント
基本的にリポジトリの中に必要なライブラリを全て持つことにします(外部依存なし(Linuxは除く))
- 生成されるEXEファイルはスタティックリンクとし単一ファイル(dll依存なし)で実行可能とする
- GUI描画のバックエンドはOpenGL3とし
GLFW-OpenGL3
,SDL2-OpenGL3
,SDL3-OpenGL3
の組み合わせで使います - アイコンフォント Font Awesomeを使います。添付
- GLFW 3.4.0 スタティックライブラリを添付
- SDL2/SDL3 スタティックライブラリを添付
- 各種画像(JPEG,PNG..etc)表示、保存用にSTB (stb_imageだけ)ライブラリを添付
- ImPlotで
ImDrawIdx="unsigned int"
を有効にする - ImGuiで日本語入力候補位置を正常化するように Input method (IME)定義
IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS
を有効にする[6]
ビルドと実行
-
Windowsのコマンドライン上でプロジェクトをダウンロードします
git clone --recurse-submodules https://github.com/dinau/imguinz
-
例えばexamplesの一つに移動します
cd imguinz/examples/glfw_opengl3_jp
-
ビルドと実行
make run # 又は zig build --release=fast run
ImGui: GUIプログラムの概略
- 上のフローチャートでグリーンの部分は定型処理なので新規プログラムにコピペで使用可能部分
これらの詳細は簡単なGUIならひとまず理解する必要のない部分 - GUIの具体的なプログラムはオレンジ色の 「:: GUIメイン :: Dear ImGui」の部分に書いていく
各種イベント処理もこの中で行う
GUIのメイン処理 Dear ImGui
メイン処理の中でWindowを一つ作ってGUI部品(ウィジェット)を並べていきます
レイアウターはなく、部品を縦横に配置していくだけなので簡単です[8]
GUI部品を縦(タテ/垂直)に並べる
上図のレイアウトを分かり易く引数を省略して書くと以下の様な仮想コードになります
// Show window
{ // defer文を使う時、このブロック分離は必須
_ = ig.igBegin(); // Windowを一つ作って開始
defer ig.igEnd (); // defer文によるWindow終了処理
//
ig.igText(); // テキストウィジェットを配置
if (ig.igButton()){ // ボタンウィジェットを配置、ボタン押下イベントもここで取る
MySaveFunction(); // 押下イベント処理を実行
}
ig.igInputText(); // テキスト入力ウィジェットを配置
ig.igSliderFloat(); // スライダーウィジェットを配置
// Window処理終了
} // ブロック分離終了
GUI部品関数を上から下に書くと、その順に画面に表示されていきます
実際のコードは関数引数を以下の様に指定します
// Show window
{
_ = ig.igBegin ("Dear ImGui", null, 0);
defer ig.igEnd ();
//
ig.igText("Hello, world %d", 123); // テキストウィジェットを配置
if (ig.igButton("Save", btnSize)){ // ボタンウィジェットを配置、ボタン押下イベントもここで取る
MySaveFunction(); // 押下イベント処理を実行
}
ig.igInputText("string", &buf, buf.len, 0, null, null); // テキスト入力ウィジェットを配置
ig.igSliderFloat("float", &fval, 0.0f, 1.0f, "%.3f", 0); // スライダーウィジェットを配置
}
GUI部品を横(ヨコ/水平)に並べる
GUI部品のデフォルト配置が縦なのでヨコに並べる時は、GUI部品の後に水平に並べる関数 igSameLine()
を呼び出します
上の様にボタンを3つ横に並べたいときは以下の順に関数を呼び出します
実際のコード
// Show window
{
_ = ig.igBegin ("Dear ImGui", null, 0);
defer ig.igEnd ();
//
if (ig.igButton("Button1", btnSize)){ // ボタン1 ウィジェットを配置
Button1Func();
}
ig.igSameLine (0, -1.0) // 次の部品を横に並べる関数
if (ig.igButton("Button2", btnSize)){ // ボタン2 ウィジェットを配置
Button2Func();
}
ig.igSameLine (0, -1.0) // 次の部品を横に並べる関数
if (ig.igButton("Button3", btnSize)){ // ボタン3 ウィジェットを配置
Button3Func();
}
}
igSameLine()の引数(0, -1.0)はデフォルト値でこれを指定しておくと適度に配置してくれます 😃
特定の値にしたい時は最初の引数が開始位置で、次がスペース量です。
GUI部品のタテ間隔を空ける
上の場合はigNewLine()
関数を挿入します
部品間隔に関する関数群
ひとまず以下のような読めばだいたい想像がつく関数が用意されていますが
詳細は省略します
igSeparator(void);
igSameLine(float offset_from_start_x,float spacing);
igNewLine(void);
igSpacing(void);
igDummy(const ImVec2 size);
igIndent(float indent_w);
igUnindent(float indent_w);
BeginGroup();
EndGroup();
AlignTextToFramePadding();
GetTextLineHeight();
GetTextLineHeightWithSpacing();
GetFrameHeight();
GetFrameHeightWithSpacing();
説明はソースコードに書かれていて
使い方はデモコードで知ることになります
最も重要な: GUIのラベルは識別子
-
GUI部品ラベルとはGUI部品関数の最初の引数ラベルのこと
ig.igButton("Save", btnSize)
の場合は「"Save"」ラベルが識別子となる -
その型は文字列
-
このラベルがその部品の識別子となるので同一スコープ内での重複は許されない
重複した場合はプログラムの動作が不規則に挙動不審であやしい動きをする (-:
最近のバージョンでは識別子が重複していると動作時に以下の様にGUI上でメッセージが表示される様になった -
WindowもGUI部品
Windowラベルも固有の識別子が必須ig.igBegin("win1") // 一つ目のWindow ... ig.igEnd() ig.igBegin("win2") // 二つ目のWindow ... ig.igEnd()
-
Windowが分かれていれば重複名OK
"Button1"ラベルは重複使用だがOKig.igBegin("win1") // 一つ目のWindow if ig.igButton("Button1",...){ } ... ig.igEnd() ig.igBegin("win2") // 二つ目のWindow if ig.igButton("Button1",...){ } ... ig.igEnd()
-
識別子の可否
GUI部品のラベル部分だけを抜き出すと
以下はアプリ内で別Windowにボタンが所属しているので"Button1"ラベルの使用はOKOK: "win1" - "Button1" OK: "win2" - "Button1"
同一Window内でもTabウィジェット内に所属するなら、そこで識別子分離(別スコープ)が起こるので重複ラベルOK
OK: "win1" - "Button1" - "tab1" - "Button1" // Tabウィジェットで分離されたので"Button1"重複はOK OK: "win2" - "Button1" - "tab1" - "Button1" - "tab2" - "Button1" // Tabウィジェットで分離されたので"Button1"重複はOK NG: - "Button1" // 同一Tab内で"Button1"重複はNG
-
同一スコープ内で同じ表示ラベルを使いたい場合
## + 任意の文字列
で識別子を作るig.igButton("Button1##bb1",..) ig.igButton("Button1##bb2",..)
##bb1
,##bb2
の部分は表示されず識別要素として使われる -
まとめ
最初のWindowラベルからたどって最後の当該GUI部品のラベルを全部並べて
Hash値を取り、それがアプリ内で重複しなければOK部品を大量にプログラムで並べたいときは
ig.igPushID(..)
ig.igPopID()
を使って意図的に識別子分離することも可能な様だ -
参考: このあたり
https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#q-about-the-id-stack-system -
識別子が不要なGUI部品
マウスでクリックできないGUI部品は識別子カウントされない
例えば igText()やセパレータ等々
次に重要な: GUI部品のラベルを隠す
部品を並べていくと勝手に表示される部品ラベルを非表示にしたい場合がある
ラベルを隠すには
ig.igSliderFloat("",...)
ig.igSliderFloat("##",...)
の様にラベル部分を""
(空文字)や##
にすれば良いが
これだと識別子重複違反になるので普通は##slider1
の様に
##
の後に任意で非重複な識別子を追加する
ig.igSliderFloat("##slider1",...)
Examplesプログラムを実行した時のスクリーンショット
ImGui-Toggle / CImGui-Toggle
トグルスイッチ・ウィジェット・ライブラリを使ってみた (2025/02)
ImGui-Knobs / cimgui-knobs
アナログ的なツマミ調整ウィジェット
ミキサー類に使える
ImSpinner / CImSpinner
スピナーウィジェット
回転系のスゴめなアイテム群
glfw_opengl3, sdl2_opengl3, sdl3_opengl3
glfw_opengl3 , sdl2_opengl3 , sdl3_opengl3
アイコンフォントを表示
glfw_opengl3_jp
glfw_opengl3_jp
日本語の表示と入力
IconFontViewer
iconFontViewer
Iconフォントビューア、部分ズーム
glfw_opengl3_image_load
glfw_opengl3_image_load
画像の表示と保存、部分ズーム
黄色の「Save Image」ボタンでキャプチャした画像は./zig-out/bin
フォルダに保存されます
保存形式はJPEG / PNG / BMP / TGA
が選択可能
glfw_opengl3_implot
glfw_opengl3_implot
ImPlotライブラリ使用デモ
ImPlot デモを「 Zig言語」で書いてみた
現状、全てではないです(残りはおいおい)
C++言語で書かれたデモを手動 (^^; でZig言語に変換しています
ChatGPTにお願いしたけど無料版なので無理でした
orz
orz
ビルドと実行
pwd
examples/imPlotDemo
make run # or zig build --release=fast run
Zig言語で書いたImPlot デモソース demoAll.zig
ImPlot使用時のImVec4
周りが多重定義でコンパイルできない(理由は不明)ので
やっつけ(TODO)な感じになっています
orz
以下はC++だったコードをZig言語で書き直したデモを実行した時の表示画像です
(C++コードと全く同じ画面なわけですが... 😃
Plots Tab
LinePlots (アニメーション)
BarGroups
BarStacks
PieCharts
Heatmaps
Histogram2D
Images
Axes Tab
LogScale
Subplots Tab
Tables (アニメーション)
Tools Tab
DragRects
コンソールウインドウを表示・非表示にする
各exampleフォルダの中の build.zig
を開いて以下の行で表示/非表示にします
デフォルト: 非表示
以下をコメントアウト: 表示
... snip ...
exe.subsystem = .Windows; // Hide console window
... snip ...
その後 make run
を実行します
ImPlotラッパー関数について
上で書いた関数変換ラッパーライブラリ
です
ImPlotの場合このライブラリを作らないと結構大変なことになるので
仕方なく(オイ) 作りました
ImPlot関数の呼び出しが簡単になるようにラッパー関数を半自動生成しています
本来は上で書いたJsonデータを使って自動生成プログラムを書くのが正攻法ですが
とりあえずJsonファイルを使わず半手動プログラムから生成しています 😃
以下は生成された関数変換ラッパーライブラリ
examples/imPlotDemo/src/zimplot.zig
Zig言語用Dear ImGuiラッパーライブラリ
ちゃんとラッパーライブラリを作ったプロジェクトがあるので
そのうちというかZig言語の正式リリース以降にさらに活発にメンテナンスされるかも
https://github.com/pdoane/zig-imgui/blob/main/src/imgui.zig
https://github.com/SpexGuy/Zig-ImGui/blob/master/zig-imgui/imgui.zig
SDL libraries
https://github.com/libsdl-org/SDL/releases
My tools version
- Git version 2.46.0.windows.1
- Make: GNU Make 4.4.1
- Zig: 0.14.0
- SDL2 2.32.0
- SDL3 3.2.6
類似プロジェクト
Language [9] | Project | |
---|---|---|
Lua | Script | LuaJITImGui |
NeLua | Compiler | NeLuaImGui |
Nim | Compiler | ImGuin, Nimgl_test, Nim_implot |
Python | Script | DearPyGui for 32bit WindowsOS Binary |
Ruby | Script | igRuby_Examples |
Zig, C lang. | Compiler | Dear_Bindings_Build |
Zig | Compiler | ImGuinZ |
SDL game tutorial Platfromer
Language [9:1] | SDL | Project | |
---|---|---|---|
LuaJIT | Script | SDL2 | LuaJIT-Platformer |
Nelua | Compiler | SDL2 | NeLua-Platformer |
Nim | Compiler | SDL3 / SDL2 | Nim-Platformer-sdl2/ Nim-Platformer-sdl3 |
Ruby | Script | SDL3 | Ruby-Platformer |
Zig | Compiler | SDL2 | Zig-Platformer |