2014年09月29日

FLTK2.0

コントロールのドッキングができる FLTK Dock (http://fltkdock.sourceforge.net/) を使ってみたくて入手したのですが、どうやら FLTK 2.0 専用のようで、FLTK 1.3 ではコンパイルできません。
そこで FLTK 2.0 を持ってきてビルドしようとしたのですが、ライブラリをビルドする時に苦労したのでメモです。

まず FLTK 2 はサブバージョンのリポジトリから直接もってくる必要があるので、svn をインストールします。自分は Tortoise SVN を使いました。説明文によれば、ユーザー名とパスワードは両方とも "ENTER" と入れればよいそうです。
FLTK のリポジトリをチェックアウトしたら ide/visualc/ にある Visual C++ のファイルを開きます。
いくつかプロジェクトが含まれていますが、そのうちの "fltk" が fltk2 のスタティックライブラリのビルド用で、"fltk_gl" が OpenGL と組み合わせる時に使うライブラリです。これをビルドし、できあがったライブラリをリンクすれば良いのですが、そう素直には行きません。

ここで作ったライブラリを自分のプロジェクトからリンクして使おうとすると、elete_associations_for の実体がないというリンカエラーが発生します。
この実体、実は src/win32/WidgetAssociation.cxx にあるのですが、このソースファイルは元のfltk プロジェクトファイルには含まれておらず、#include “win32/WidgetAssociation.cxx”という感じで run.cxx から直接インクルードされています。
ソースファイルを連結しているだけなので問題ないように見えるのですが、なぜかダメみたいです。
というわけで、win32/WidgetAssociation.cxx を fltk プロジェクトに追加し、再びビルドします。

これでリンカエラーが出ずに、FLTK2 が使えるようになりました。

そして当初の目的であった FLTK Dock を使おうとしたら、なんと古いバージョンの FLTK2 用らしく、いろいろなところでコンパイルエラーが。
一気にモチベーションがさがり、それっきり FLTK を触っていません…。
posted by JUNOSOFT at 05:03| Comment(0) | プログラミング

2014年09月04日

FLTK

必要最低限の機能を押さえていて、インストール&ビルドが楽、ということで最近 FLTK 1.3 をテストしています。
ボタンやツリービュー、メニュー、タブなど一通りのコントロールがそろっていて、なによりも無改造で日本語に対応している点がよいですね!
フォントを変更する必要すらありません。FLTK は文字列を utf-8 で扱っているので(wchar_t ではなく、マルチバイト文字列であることに注意)、それさえ気を付ければ簡単に日本語を表示する事ができます。

まず普通にアルファベットを表示したりするときは

Fl_Window *wnd = new Fl_Window(0, 0, 320, 240, “HELLO”);

のようにします。日本語で表示させたい時はまず UTF8 に変換する必要がありますから、

std::string utf8(const std::string &s);

とかいう適当な変換関数を用意して、

Fl_Window *wnd = new Fl_Window(0, 0, 320, 240, utf8(“ウィンドウ”).c_str());

のようにすればいいです…といいたいところですが、これはうまく行きません。
Fl_Window をはじめとして FLTK のコントロールはコンストラクタで渡された文字列ポインタをそのまま保持しているみたいです。
そのため文字列の実体がずっと存在することが前提となっているんですね。
ところが上記のような指定方法だと、文字列の実体は初期化式を抜けた時に破棄されてしまい、ウィンドウのタイトルとして不正な文字列が使われてしまいます。

これを回避するには、単純に static な文字列を指定するか、あるいは文字列引数を省略して(コンストラクタでの文字列指定はオプション引数になっている)
とりあえず生成してしまい、あとから copy_label でタイトルを指定する必要があります。

Fl_Window *wnd = new Fl_Window(0, 0, 320, 240);
wnd->copy_label(utf8(“ウィンドウ”).c_str());


コンストラクタ以外でタイトルを指定するには label() と copy_label() があるのですが、
label() だとコンストラクタで指定するのと同じで文字列のポインタがそのまま保持されるだけになってしまい、ダメです。
copy_label() ならその名の通り文字列のコピーを保持するようになるため、安心して扱う事が出来ます

ちなみに 文字コード変換の関数はこんな感じで作れます

static std::wstring ToWide(int codepage, const std::string &s) {
if (s.empty()) return std::wstring();
int len = MultiByteToWideChar(codepage, 0, &s[0], -1, NULL, 0);
len--; // 終端の\0は不要
if (len <= 0) return std::wstring();
std::wstring ws(len, L'\0');
MultiByteToWideChar(codepage, 0, &s[0], -1, &ws[0], ws.length());
return ws;
}

static std::string ToMBSC(int codepage, const std::wstring &ws) {
if (ws.empty()) return std::string();
int len = WideCharToMultiByte(codepage, 0, &ws[0], -1, NULL, 0, NULL, NULL);
len--; // 終端の\0は不要
if (len <= 0) return std::string();
std::string s(len, '\0');
WideCharToMultiByte(codepage, 0, &ws[0], -1, &s[0], s.length(), NULL, NULL);
return s;
}

std::string utf8(const std::string &s) {
const int SJIS = 932;
std::wstring ws = ToWide(SJIS, s)
return ToMBSC(CP_UTF8, ws);
}

FLTK 2.0 もためしてみようかな


posted by JUNOSOFT at 06:38| Comment(0) | プログラミング