VCFのあれこれ追記
- オンラインリファレンス
- http://vcf-online.org/docs/ref_manual/index.html
- ライセンスについて
- http://vcf-online.org/license
スタティックライブラリとDLLの2種類用意してあるって話のようだが、どれがDLL読み込み用libファイルでどれが中身入りlibファイルなのかわけわかめ。
いや、それっぽいのはVSのプロジェクト設定ダイアログに表示されてるけど見つからね。
Visual Component Framework
WindowsでGUIアプリを作る際に、Win32API直叩きは面倒過ぎるし、WinFormsもWPFも重いし、MFCとかは未来無いし、だからって自作ライブラリ作っても大した汎用性持たせられないし、ということで他に良いWindows用GUIライブラリは無いかと探していたら、良さそうな物を発見。
まだ実際にこれを利用してコードを書くということはしてないけども、デモアプリケーションの様子を見る限りではなかなか良さそう。見た目も悪くないです。
unicode(UTF-16)に対応しているからwchar_tもwstringも使えます。
ライブラリは、コア、GUIコントロール、グラフィック、その他色々と分かれているそうで、CUIなアプリにもGUI・グラフィック以外のクラスや関数は使えるらしい。
欠点は、ググった限りでは日本語資料が皆無で英語資料に頼るしかない、及び対応プラットフォームがMacとWindows(NT以降)だけっぽいこと。
Gtkmmみたいな感じでコード書けたら.Netはプロトタイプ作成だけに使って、本番用はこっちで作るようにしようかな。
カスタムコントロール作るのが大変じゃなければいいなぁ。
gtkmm/GUIプログラミング - 2
今回はwidgetをクラスで表現してそれを表示するところまで書いてみます。
何はともあれ例から。
#include <gtkmm/main.h> #include <gtkmm/window.h> #include <gtkmm/button.h> class MainWindow : public Gtk::Window { Gtk::Button mButton; public: MainWindow(); ~MainWindow(); }; MainWindow::MainWindow() : mButton("Hello World!") { set_border_width(10); add(mButton); mButton.show(); } MainWindow::~MainWindow(){} int main(int argc, char *argv[]) { Gtk::Main kit(argc, argv); MainWindow aWindow; kit.run(aWindow); return 0; }
このように希望するウィジェットのクラスを継承することで、ウィジェットをクラスとして表現することが出来ます。
コンテナは他のウィジェットをメンバとして持つことが出来ます。この場合、ボタンウィジェットをメンバとして持っています。
ボタンウィジェットはコンストラクタの引数に描画するラベルの文字列を取るのでMainWindowのコンストラクタでそれを指定します。
set_border_width()メソッドはGtk::Windowから参照できるメソッドで、HTMLで言うとパディングの部分に当たる数値の設定用メソッドです。
また、空ウィンドウの時のウィンドウもそうでしたが、オブジェクトを生成しただけでは可視化されません。
そこでadd()メソッドを用いてMainWindowのコンテナにmButtonを追加します。
その後、mButton自身が持っているshow()メソッドを用いて可視化します。
なお、show()の反対の役割をするのがhide()メソッドです。ただしhideというよりはfinishみたいなもんです。Gtk::Main::runに渡したウィジェットオブジェクトでこのメソッドを実行するとプログラムが正常終了します。
あとはこのようにクラス定義を行ったオブジェクトをmain関数で生成しGtk::Main::runに渡します。
後で読んで内容を理解できるか不安だけど、これで第二回まとめを終了します。
gtkmm/GUIプログラミング - 1
CではなくてC++で書きたいという理由でGTK+をすっ飛ばしてgtkmmを使い始めてみました。
日本語の満足いくチュートリアルがパッと見つからなかったのでここのドキュメントページに載ってるチュートリアルっぽいリファレンスと格闘中。
とりあえず、ここまで学習したことのまとめ。
準備
gtkmmのライブラリ等は適当にダウンロード。おいらはubuntuのリポジトリから適当に放り込みました。
もしgtkmmを使って作ったアプリを配布する場合、使用者のPCにgtkmmのランタイムが必要。
Gladeを使うならglademmがあるとインターフェースの切り替えが楽になって便利。ただし実行時にはglademmのランタイムが必要。
makeについて
方法その1:全自動。anjutaとかkdevelopに頼る。おいらみたいな怠惰な人向け。違う環境に移った時にきっと慌てます。
方法その2:全手動。コンパイルする時に `pkg-config gtkmm-2.4 --cflags` を、リンクする時に `pkg-config gtkmm-2.4 --libs` をそれぞれオプションに指定すれば大丈夫なはず。
空のウィンドウを表示。
#include <gtkmm.h> int main(int argc, char *argv[]) { Gtk::Main kit(argc, argv); Gtk::Window window; Gtk::Main::run(window); return 0; }
これで空っぽのウィンドウが表示されます。
#include <gtkmm.h>
gtkmmのヘッダファイルを全てインクルードします。
必要に応じてインクルードする場合、gtkmmディレクトリ以下のヘッダファイルを適宜インクルードします。
Gtk::Main kit(argc, argv);
gtkmmの初期化。変数名はkitでなくてもいいが、参考にした資料ではkitという名前になっていたのでそのまま利用。
コマンドライン引数を欲しがるので与えてあげます。
Gtk::Window window;
Gtk::Windowクラスのオブジェクトを定義します。
Buttonとかのウィジェットの場合は、このように生成した後にadd()メソッドでコンテナに追加し、show()メソッドで可視化してやると表示されます。
メインとなるウィンドウの場合はshow()メソッドではなく、後述するGtk::Main::run関数で有効化して可視化します。
Gtk::Main::run(window);
windowを可視化し、メインループに入ってイベントの発生を待ちます。
ウィンドウの×ボタンを押されるなどして終了イベントが発生し、最後のフェーズまで処理が終了するとrun関数が終了し、この次の行に処理が移ります。
Gtk::Main::runはstaticメンバ関数なので、先に生成したkitと合わせて kit.run(window) とすることもできます。
とりあえず第一回gtkmmまとめ終了。
関数ポインタ
すぐやり方を忘れるので覚えているうちにメモ。
void hoge(){} namespace foo{ void piyo(){} } class bar { public: void boon(){} static void ban(){} }; // typedef 戻り値 ポインタの型名(引数リスト); 引数部分の書き方はC/C++の文法に準じる。 typedef void (*FP)(); int main(){ FP fp1 = hoge; // または &hoge FP fp2 = foo::piyo; // または &foo::piyo FP fp3 = bar::ban; // または &bar::ban void (bar::*fp4)() = &bar::boon; // bar::boonはだめ。ポインタ名(typedefなら型名)の部分にクラス名が必要。 bar b; bar *a = &b; fp1(); fp2(); fp3(); (b.*fp4)(); (a->*fp4)(); return 0; }
グローバル名前空間の関数、特定の名前空間の関数、スタティックメンバ関数は「どこに属しているか」が違うだけで他は同じなので全部が同様の方法で出来る。ってことだと思う。
普通のメンバ関数はどのインスタンスに属している状態で呼ばれているのか分からないと仕事ができない(見当違いのアドレスがthisポインタに入ったりする)ので、所属インスタンスを特定するために適切なインスタンスが必要。
実際にはワケ分からんアドレスがthisに入ったりする前にコンパイラに怒られます\(^o^)/
通常のメンバ関数の時だけポインタ名にクラス名を指定する理由は謎。普通の関数ポインタと区別するためっぽいけど・・・。
segmentation fault
セグメントはメモリ上に特定のデータ量でコード及びデータが展開された領域のこと。
んでここから外れた所をポインタで参照したら出るエラーが「segmentation fault」。
変数に放り込める最大値を知る。
unsignedな変数ならsignedにキャストして-1を放り込んでunsignedに戻せば達成できます。*1
ですが、コンパイラに付属のヘッダファイルから直値で知れればそっちの方が処理速度は上がります。
ってことで、各変数に放り込める最大値がマクロで定義されているのでその取得方法。
#include <iostream> #include <climits> int main(){ std::cout << "charのビット数: " << CHAR_BIT << std::endl; std::cout << "多バイト文字の最大バイト数: " << MB_LEN_MAX << std::endl; std::cout << "charの最大値: " << CHAR_MAX << std::endl; std::cout << "charの最小値: " << CHAR_MIN << std::endl; std::cout << "signed charの最大値: " << SCHAR_MAX << std::endl; std::cout << "signed charの最小値: " << SCHAR_MIN << std::endl; std::cout << "unsigned charの最大値: " << UCHAR_MAX << std::endl; std::cout << "short intの最大値: " << SHRT_MAX << std::endl; std::cout << "short intの最小値: " << SHRT_MIN << std::endl; std::cout << "unsigned short intの最大値: " << USHRT_MAX << std::endl; std::cout << "intの最大値: " << INT_MAX << std::endl; std::cout << "intの最小値: " << INT_MIN << std::endl; std::cout << "unsigned intの最大値: " << UINT_MAX << std::endl; std::cout << "long intの最大値: " << LONG_MAX << std::endl; std::cout << "long intの最小値: " << LONG_MIN << std::endl; std::cout << "unsigned long intの最大値: " << ULONG_MAX << std::endl; return 0; }
Cでこれらを利用するときは limits.h をインクルードする。
*1:負数を2の補数で表現するCPUでは-1で全てのビットが反転するため。将来的にこれ以外の手法で負数を表現するCPUが出てきたら使えない。