VC++フォームのUI、何とかしたいのだけれど、ずぼらのめんどくさがり屋はIDEを避けて通りたいので、手打ち&DOS窓(コマンドプロンプト)にcl入れてコンパイル。
試しに、VC++フォームでUIのイベント処理を呼び出すだけのサンプルを作ってみました。
<注意点>
・下記clコマンドラインだと、エクスプローラから起動してもDOS窓は表示されません(つまり、Windows アプリケーションとして作成されたらしい)。
・デザイナを利用すれば、「デリゲートオブジェクトのインスタンス化」「イベント発生元にデリゲートを追加」「発生イベントを処理する空のメソッド」を三点セットで自動生成してくれるようです。
・Invalidate() はコントロール領域を無効化するので、ソフト的にイベント(再描画要求)を発生させる事が出来ます。
・最小化したフォーム画面の再描画後の状態は、手抜きです。
【デリゲートの概要】
・デリゲートは、CやC++の関数へのポインタに似た機能です。
・デリゲートのメソッド呼出しは、関数へのポインタと同様です。
・デリゲート自体、オブジェクトです。
①デリゲートの宣言
修飾子 delegate 戻り値の型 デリゲート型名(引数リスト); *1 *2
②暗黙的なデリゲートコンストラクタ
デリゲート型名(対象オブジェクト、メソッドのポインタ);
③デリゲートの実体化(インスタンス生成と追加)
デリゲート型名 ^変数名 = gcnew デリゲート型名(対象オブジェクト、メソッドのポインタ); *3
④デリゲートの使用例
private delegate void deletypename(System::String ^s);
ref class test {
public :
void method(System::String ^str) {
System::Console::WriteLine("String = " + str);
}
};
void main()
{
test ^test1 = gcnew test;
deletypename ^callptr = gcnew deletypename(test1, &test::method);
callptr("文字列表示。");
}
⑤実行結果
String = 文字列表示。
【イベントの概要】
・イベントの目的は、デリゲート型のフィールド(変数)を非公開にすることです。
・つまり、デリゲート型のオブジェクトを直接操作させること無く、コールバックの仕組みを実現することです *4。
①イベントの宣言
修飾子 event デリゲート型名 ^イベント名;
【上記を前提に、VC++フォームのUIイベントに当て嵌めると】
・対象のコントロールが公開しているイベントにデリゲートを登録(追加)する事で、イベント処理が呼び出されます。
・Click イベント
public delegate void EventHandler(Object ^sender, EventArgs ^e);
public event EventHandler ^Click;
button1->Click = gcnew EventHandler(this, &Form1::button1_Click);
(ボタンが押された時、コントロールから呼ばれるメソッド)
void button1_Click(Object ^sender, EventArgs ^e) {}
・Paint イベント
public delegate void PaintEventHandler(Object ^sender, PaintEventArgs ^e);
public event PaintEventHandler ^Paint;
this->Paint = gcnew PaintEventHandler(this, &Form1::form1_Paint);
(再描画要求が発生した時、コントロールから呼ばれるメソッド)
void form1_Paint(Object ^sender, PaintEventArgs ^e) {}
*1:対象オブジェクトは、メソッドを宣言しているマネージ型である必要があります。
*2:デリゲートの宣言で指定した同型の「戻り値や引数」と異なるメソッドを指定できません。
*3:デリゲートには、同型の「戻り値や引数」を持つメソッドを += 演算子を使って幾つでも追加することが出来ます。
*4:外部からデリゲートを登録する仕組みを提供することに同じ。
お試し環境
WindowsXP 32bit Edition
Visual C++ 2008
/*---- VC++ Form 作成 ----------------- コマンドライン --------------------*/
D:\vc2008\dllchk>cl /clr testpp.cpp /link /subsystem:windows /entry:mainCRTStartup
/*----------------------------------------------------------------------------*/
/*---- testpp.cpp -------------------- お試しソース ------------------------*/
#using <system.dll>
#using <system.drawing.dll>
#using <system.windows.forms.dll>
using namespace System::Windows::Forms;
ref class suText : public System::Windows::Forms::RichTextBox {};
ref class suButton : public System::Windows::Forms::Button {};
ref class suForm : public System::Windows::Forms::Form {
public :
suForm() {
initCompo();
}
~suForm() {}
private :
suText ^text1;
suButton ^button1;
System::Windows::Forms::Label ^label1;
System::Drawing::Point pt;
System::String ^str;
void initCompo()
{
text1 = gcnew suText;
text1->Location = System::Drawing::Point(50, 50);
text1->Size = System::Drawing::Size(100, 150);
text1->BackColor = System::Drawing::Color::FromArgb(255, 255, 180);
text1->Name = "text1";
text1->Text = "求む入力!";
text1->MouseDown += gcnew System::Windows::Forms::MouseEventHandler(this, &suForm::text1_MouseDown);
button1 = gcnew suButton;
button1->Location = System::Drawing::Point(75, 220);
button1->Size = System::Drawing::Size(70, 20);
button1->BackColor = System::Drawing::Color::FromArgb(180, 255, 255);
button1->Name = "button1";
button1->Text = "未確認";
button1->Click += gcnew System::EventHandler(this, &suForm::button1_Click);
label1 = gcnew Label;
label1->Location = System::Drawing::Point(200, 120);
label1->Size = System::Drawing::Size(150, 20);
label1->Name = "label1";
label1->Text = "コンパイルエラーが来たぁ";
this->Location = System::Drawing::Point(50, 50);
this->ClientSize = System::Drawing::Size(400, 300);
this->StartPosition = FormStartPosition::Manual;
this->Name = "form1";
this->Text = "サンプルプログラム";
this->Paint += gcnew System::Windows::Forms::PaintEventHandler(this, &suForm::form1_Paint);
this->Controls->Add(text1);
this->Controls->Add(button1);
this->Controls->Add(label1);
}
System::Void text1_MouseDown(System::Object ^sender, System::Windows::Forms::MouseEventArgs ^event) {
pt = System::Drawing::Point(event->X, event->Y);
str = "X = " + event->X + ", Y = " + event->Y + ", Button = " + event->Button.ToString();
Invalidate();
}
System::Void button1_Click(System::Object ^sender, System::EventArgs ^event) {
label1->Text = "ボタンが押されました。";
label1->ForeColor = System::Drawing::Color::Red;
button1->Text = "押下";
button1->Enabled = false;
}
System::Void form1_Paint(System::Object ^sender, System::Windows::Forms::PaintEventArgs ^e) {
System::Drawing::Graphics ^g = e->Graphics;
System::Drawing::Brush ^brush = gcnew System::Drawing::SolidBrush(System::Drawing::Color::Blue);
g->DrawString(str, Font, brush, 200, 160);
g->FillRectangle(brush, pt.X + 150, pt.Y, 10, 10);
label1->Text = "コンパイルエラーが来たぁ";
label1->ForeColor = System::Drawing::Color(ForeColor);
button1->Text = "未確認";
button1->Enabled = true;
}
};
void main()
{
Application::Run(gcnew suForm);
}
/*----------------------------------------------------------------------------*/
/*============================================================================*/