...ing logging 4.0

はてなブログに移行しました。D言語の話とかいろいろ。

いろいろなコントロール

controls_on_d.PNG

いろいろなコントロールを定義してみたの図.
細かい仕様は置いといて,まだ Menu クラスを全然考えていないのと,コントロールのレイアウトを支援する機能も作らないとな〜.
RAD での開発ができないから,全部コードでレイアウトしなきゃいけないし.
はてさて,今月の C Magazine の記事を参考にしてるけども結構できるもんだ.
他の GUI ライブラリだと,描画関係は専用のクラスを作っているみたい.
そら, HDC を Win32API で操作して描くのは大変だものな.

例によってユーザの書くプログラムは続きを参照.
ユーザに main.d の中で UserMain() を定義してもらう制約を付けて,スタートアップコードをライブラリ側に移した.
なのでこれが本当に main.d の全容.
だいぶそれらしくなったかな?


//
// ForDを使ったサンプル
//
import ford;
import std.string;

public int user_main()
{
// アプリケーションクラスの生成
g_app = new Application;

// フレーム生成
Frame frame = new MyFrame;
frame.create("Hello, world!", CW_USEDEFAULT, CW_USEDEFAULT, 400, 300);

// アプリケーションにフレームを登録してメッセージループに入る
g_app ~= frame;
g_app.messageLoop();

return 0; // 正常終了
}

public class MyFrame : Frame
{
private Button button1;
private Button button2;
private TextField text;
private CheckBox check;
private RadioButton radio1;
private RadioButton radio2;
private RadioButton radio3;
private Label label;
private char[] point;

// this()内でCreateWindow()できるならこの関数の処理はthis()へ移せる
public override void initializeComponent()
{
// フレーム自身のイベントをセット(ちなみに~=演算子はpublic)
this.onDraw ~= &drawCanD;
this.onMouseDown ~= &mouseDown;
this.onMoveWindow ~= &moveWindow;

// ボタン1を生成
button1 = new Button;
this ~= button1; // コンテナに登録 // これはcreate()後に記述したい!!
button1.onClick ~= &showMessageOK; // ボタン押下時の処理をセット
button1.create("OK", 0, 0, 100, 25);

// ボタン2を生成
button2 = new Button;
this ~= button2; // コンテナに登録 // これはcreate()後に記述したい!!
button2.onClick ~= &showMessageYesNo;
button2.create("Yes/No", 110, 0, 100, 25);

// テキストボックスを生成
text = new TextField;
this ~= text;
text.create(r"テスト", 0, 50, 300, 25);

// チェックボックスを生成
check = new CheckBox;
this ~= check;
check.create(r"チェックボックス", 0, 100, 200, 25);

// ラジオボタン1を生成
radio1 = new RadioButton;
this ~= radio1;
radio1.create(r"ラジオ1", 300, 0, 200, 25);

// ラジオボタン2を生成
radio2 = new RadioButton;
this ~= radio2;
radio2.create(r"ラジオ2", 300, 25, 200, 25);

// ラジオボタン3を生成
radio3 = new RadioButton;
this ~= radio3;
radio3.create(r"ラジオ3", 300, 50, 200, 25);

// ラベルを生成
label = new Label;
this ~= label;
label.create(r"D言語Windowsもできる" "\r\n" r"ラベルも作れる",300,100,200,50);
}

// ボタン1押下時に呼ばれる
public void showMessageOK(Component o)
{
MessageBox( this.hWnd, r"OKボタン", "showMessageOK",
MB_OK | MB_ICONINFORMATION);
text.text = r"OKボタンを押しましたね!";
}

// ボタン2押下時に呼ばれる
public void showMessageYesNo(Component o)
{
MessageBox( this.hWnd, r"Yes/Noボタン", "showMessageYesNo",
MB_YESNO | MB_ICONINFORMATION);
text.text = r"Yes/Noボタンを押しましたね!";
}

// フレームに描画する必要が生じたときに呼ばれる
public void drawCanD(HDC dc)
{
char[] message = r"D言語Windowsもできる";
RECT r;
GetClientRect( hWnd, &r);
HFONT font = CreateFontA( 80, 0, 0, 0, FW_EXTRABOLD, FALSE, FALSE,
FALSE, /*ANSI_CHARSET*/ SHIFTJIS_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
r"MS明朝");
HGDIOBJ old = SelectObject( dc, cast(HGDIOBJ) font);
SetTextAlign( dc, TA_CENTER | TA_BASELINE);
TextOut( dc, r.right / 2, r.bottom / 2, message, message.length);
TextOut( dc, r.right / 2, 80 + r.bottom / 2, point, point.length);
// ウィンドウ座標を描画
SelectObject( dc, old);
}

// フレーム上でマウスを押したときに呼ばれる
public void mouseDown(Component c, int x, int y)
{
MessageBox(hWnd, r"フレームをクリック", r"フレームをクリック",
MB_OK | MB_ICONINFORMATION);
}

// フレームが移動/サイズ変更したときに呼ばれる
public void moveWindow(Component c, int x, int y)
{
point = "(left,top) = (" ~ std.string.toString(x) ~ "," ~ std.string.toString(y) ~ ")";
// ウィンドウ全体を再描画
this.redraw(Component.RedrawFlag.ERASE);
}
}

イベントハンドラの部分は,最初は Java 風に書いていたけど, delegate を使うことで C# 風になった.
なんか,それだけでも D 言語のパワーが垣間見えるような気がした・・・のは気のせいか?(^^;
このサンプルでは MyFrame クラスの中にイベントハンドラを定義して Frame.onXXXXX の delegate に入れている.
これらのイベントハンドラを他のクラスで宣言してやってうまく繋いでやれば, State パターンが簡単に実装できそう.
やっぱりこれ必要だし.
できることなら MVC アーキテクチャにできればいいなぁ,とか思うだけ思ってみたり.

さて,レポートも提出したので,ちょっと遊んでみるか.