VC++フォームだからこそ、コマンドプロンプトでEXE?

|

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);
}

/*----------------------------------------------------------------------------*/
/*============================================================================*/