サンプルアプリケーション
なにやらダウンロードファイルが消えていたようなのでアップし直しました。
誰も気がつかないだろうけど。
ついでに balor を使ったサンプルアプリケーションもアップしました。
fbx 形式ファイルを読み込んで画像を描画できます。
この程度のUIを適当に作る分には balor は快適だと感じていますが
やはりUIエディタが欲しいところ。
画像ビューアのサンプル
メニューまたはショートカットキーから画像ファイルを開いて表示するサンプルコードです。
画像が大きい場合はスクロールバーが表示されます。
#include <Windows.h> #include <balor/graphics/all.hpp> #include <balor/gui/all.hpp> using namespace balor::graphics; using namespace balor::gui; int APIENTRY WinMain(HINSTANCE , HINSTANCE , LPSTR , int ) { Frame frame(L"ImageViewer"); Bitmap bitmap; typedef Menu::ItemInfo Item; Item fileMenuItems[] = { Item(L"開く(&O)\tCtrl+O", Key::Modifier::ctrl | Key::o), Item(), Item(L"終了(&X)\tAlt+F4", Key::Modifier::alt | Key::f4) }; Item menuBarItems[] = { Item(L"ファイル(&F)", fileMenuItems), Item(L"ヘルプ(&H)", [&] (Menu::Click& ) { MsgBox::show(L"Image Viewer Ver 1.0", L"バージョン情報"); }) }; MenuBar menuBar(menuBarItems); frame.menuBar(&menuBar); frame.onShortcutKey() = [&] (Frame::ShortcutKey& e) { switch (e.shortcut()) { case Key::Modifier::ctrl | Key::o : { OpenFileDialog dialog; dialog.filter(L"画像ファイル\n*.bmp;*.gif;*.png;*.jpg;*.jpeg;*.tiff\n\n"); if (dialog.show(frame)) { bitmap = Bitmap(dialog.filePath()); if (bitmap != nullptr) { // ウインドウサイズが画像サイズ以下ならスクロールできるようにする。 frame.scrollMinSize(bitmap.size()); frame.invalidate(); } } e.handled(true); } break; case Key::Modifier::alt | Key::f4 : { frame.close(); e.handled(true); } break; } }; frame.onPaint() = [&] (Frame::Paint& e) { e.graphics().clear(); if (bitmap != nullptr) { Graphics bitmapGraphics(bitmap); // スクロール分ずらして画像をコピーする。 e.graphics().copy(frame.scrollPosition(), bitmapGraphics); } }; frame.runMessageLoop(); return 0; }
balor1.0.1 リリース
balor バージョン 1.0.1 をリリースしました。
ダウンロードする。
変更点
- balor::gui::ColorDialog を追加。
- balor::gui::FontDialog を追加。
- balor::gui::Splitter を追加。
- balor::gui::Control::zOrder の数字の意味を逆順に変更。
子コントロールを追加するたびに zOrder が変化するのは使いにくい為。
- イベント名が現在進行形、現在形、過去形の3種類あったのを過去形を現在形に統合して2種類に変更。
balor::gui::Frame、balor::gui::ListView、balor::gui::Tab、balor::gui::TreeView に影響。
この修正に伴い、Tab::Item::page をタブに追加する時に親コントロールをタブコントロールに変更するようにした。
それに伴って関連する名前を全て変更。
balor と WIN32 API の連携
balor は WIN32 API と連携しやすいように作られています。
balor の多くのクラスは WIN32 API に登場するハンドルのラッパーとして振舞います。
例えば Control クラスとその派生クラスは HWND ハンドルのラッパーです。
このようなラッパークラスでは HWND ハンドルへの自動変換(operator HWND())が用意されます。
Frame frame(L"test"); Button button; // operator HWND() は null チェックにも使用できる。 if (!button) { button = Button(frame, 0, 0, 0, 0, L"button"); // HWND を引数に取る WIN32 API にそのまま渡す事ができる。 HWND parent = GetParent(button); }
以下は、クラスと WIN32 API ハンドルの対応表です。
クラス | ハンドル |
---|---|
Bitmap | HBITMAP |
Brush | HBRUSH |
Cursor | HCURSOR |
Font | HFONT |
Graphics | HDC |
Icon | HICON |
ImageList | HIMAGELIST |
Pen | HPEN |
Region | HRGN |
Control とその派生クラス | HWND |
Menu::Item | HMENU |
FileStream | HANDLE |
Registry | HKEY |
Module | HMODULE/HINSTANCE |
balor と STL の連携
balor は C++ 標準ライブラリである STL と連携して使いやすいように作られています。
例えば balor の関数引数でしばしば使われる ArrayRange は
様々な配列表現をそのまま関数に渡せるようにします。
Bitmap bitmap(100, 100, Bitmap::Format::palette8bpp); // ArrayRange 引数に固定長配列を渡す。 Color staticArray[] = {Color::red(), Color::green(), Color::blue()}; bitmap.palette(staticArray); // ArrayRange 引数に vector を渡す。 std::vector<Color> stdVector; stdVector.push_back(Color::red()); stdVector.push_back(Color::green()); stdVector.push_back(Color::blue()); bitmap.palette(stdVector); // ArrayRange 引数にポインターと配列サイズを渡す。 Color* pointer = staticArray; bitmap.palette(ArrayRange<const Color>(pointer, 3));
また、同様に関数引数でしばしば使われる StringRange は
様々な文字列表現をそのまま関数に渡せるようにします。
String s(L"abc"); // String::compareTo は StringRange を引数に取るので // 文字列ポインタ, String, StringBuffer, wstring を渡すことができる。 s.compareTo(L"abc"); s.compareTo(String(L"abc")); s.compareTo(StringBuffer(L"abc")); s.compareTo(std::wstring(L"abc"));
上記コードにでてくる balor::String は .NET や Java の String に
似た機能を持ったクラスですが、std::wstring と自動的に相互変換できます。
コピー禁止クラスと右辺値参照
balor では多くのクラスでコピーが禁止されています。
Control クラスはコピー禁止なのでその派生クラスである Button クラスもコピー禁止です。
Button b0, b1;
b0 = b1; // コンパイルエラー!コピーは禁止されている。
これまでコピー禁止クラスといえば
- STL コンテナに格納できない。
- 関数の戻り値にできない。
- 任意のタイミングで初期化できない。
このような不便があったため、コピー禁止クラスは new 演算子でヒープメモリに割り当てて
スマートポインタで管理するのが定石でした。
しかし Visual C++ 2010 で右辺値参照がサポートされた事で
ムーブセマンティクスを実装できるようになり、上記の問題は解決されました。
std::vector<Button> buttons; buttons.push_back(Button()); // STL コンテナに格納できる。 Button button = getMyButton(); // 関数の戻り値にできる。 button = Button(frame, 0, 0, 0, 0, L"button"); // 任意のタイミングで初期化できる。
具体的には右辺値参照コンストラクタと右辺値参照代入演算子で
ムーブセマンティクスを実装しています。
このため、balor ライブラリではクラスに対してメモリ割り当てを強制しません。
もちろん、ポリモフィズムやリファレンスカウントが必要な場合はこれまで通り
ヒープメモリに割り当てしてスマートポインタで管理することも可能です。