ysuga.net

This page is my hobby page! Robots, Inline skates, Rugby, and more!!

.NET frameworkを使ったGUIのRTCへの追加

.NET frameworkのWindowsFormを使います

シンプルに説明するために,若干汚いコードを書いています.
この技術は,RTコンポーネント作成だけではなくて,GUIを備えたWindowsアプリケーションをフリーで作成する場合に共通して使える内容です.

Formを追加します

Visual C++と.NETの連携です.自分自身が不慣れなので,図を交えてすこし丁寧に説明します.

まずはメニューからフォームを追加します.

Add Form

Add Form

フォームに名前をつけてください.これがFormクラスの名前になります.

Name Form Class

Name Form Class

共通言語ランタイムサポートをONにします.「はい(Y)」をクリックしてください.

CLR Support OK

CLR Support OK

Formのデザインを変更します

この変はVBを使ったことがある人なら問題ないでしょう.

Form Designer

Form Designer

*2008年6月27日追記: VC2008を使っていると,うまくツールボックスを使えない障害があります.

これは.Net Frameworkの更新を怠っているからですが,「ソリューションのプロパティ」→「共通プロパティ」→「Frameworkと参照」で,「対象とするFramework(G)」を「.Net
Framework 2.0」に選択すれば直ります.

プロパティビューからボタンのキャプションやオブジェクト名を変更できます.

Change Property of Control

Change Property of Control

ボタンとエディットボックスを追加しました.

Editbox and Button are added

Editbox and Button are added

最終的にそれぞれのプロパティの変更点は以下のようになっています.

オブジェクト button1 button2 TextBox
プロパティ デザイン-Name countUpButton sendButton textBox1
表示-Text CountUp(&C) Send(&S) Please Input Message

マネージドC++コードから,C#のFormを呼び出します

コードを編集していきます.とりあえず表示部分だけ説明しますね.Javaで言うJNIに良く似たインタフェースです.

Managed C++ Code file

Managed C++ Code file

ここまでの編集で作成したソースファイルは3つ.

  • SettingPanel.h
  • SettingPanel.resx
  • SettingPanel.cpp

SettingPanel.cppはC++コード.SettingPanel.hはC#コードになっています.不思議ですがSettingPanel.cppからSettingPanel.hをインクルードしてもコンパイルが通ります.これは共通言語ランタイムサポートをONにしている恩恵です.

つまりSettingPanel.cppを仲介役として,C#コードであるFormにアクセスができ,またその逆も可能ということです.

変更前(SettingPanel.cpp)

#include “SettingPanel.h”

変更後(SettingPanel.cpp)

#include “SettingPanel.h”

using namespace PeriodicConsoleOut;

void SettingPanel_createForm(void) {

Application::Run(gcnew SettingPanel());

}

これで表示するための関数が実装されました.ただもともとのコンポーネントのコードから,このcreateFormメソッドを呼び出さなくてはなりません.

変更前(PeriodicConsoleOut.ccp) main関数内

int main (int argc, char** argv)

{

RTC::Manager* manager;

manager = RTC::Manager::init(argc, argv);

~中略~

// run the manager in blocking mode

// runManager(false) is the default.

manager->runManager();

// If you want to run the manager in non-blocking mode, do like this

// manager->runManager(true);

return 0;

}

変更後(PeriodicConsoleOut.cpp) main関数内

void SettingPanel_createForm(void); //SettingPanel.cpp内のグローバル関数を使用するために,関数を宣言.

int main (int argc, char** argv)
{
RTC::Manager* manager;
manager = RTC::Manager::init(argc, argv);
~中略~
// run the manager in blocking mode
// runManager(false) is the default.
//manager->runManager(); //デフォルトのrunManagerメソッドをコメントアウト.

// If you want to run the manager in non-blocking mode, do like this
manager->runManager(true);  //runManagerメソッドをノンブロッキングモードで呼び出すと,コントロールがすぐに返ってきます.

SettingPanel_createForm();  //そして直ちにFormを作成します.createFormメソッド内のApplication::Run()メソッドはモーダルなFormを作成するので,Formを閉じない限りmain関数は終了しません.
return 0;
}

Formと変数のやり取りをします.

Formにイベントハンドラを追加します

それぞれのボタンをダブルクリックすると,自動的にイベントハンドラコードが生成されます.

今回追加した二つのボタンを両方ともダブルクリックすると,下記のようなコードが生成されます.

#pragma endregion

private: System::Void countUpButton_Click(System::Object^ sender, System::EventArgs^ e) {
}

private: System::Void sendButton_Click(System::Object^ sender, System::EventArgs^ e) {
}

};

ちなみに,ソリューションエクスプローラからSettingPanel.hを開いても,デザインビューしか開きません.コードを変更するときは右クリックをして,メニューからコードの表示を選びます.

Menu > Show Code

Menu > Show Code

変数のやりとりについては2種類あります.

まずはSettingPanel.cppにあるグローバル変数を介して行います.

変更後(SettingPanel.cpp)

#include <string>

std::string stringBuffer= 0; //このようにヘッダーファイル(C#コード)の前で変数を宣言することで,C#コード内で変数を操作することができるようになる.

#include “SettingPanel.h”
using namespace PeriodicConsoleOut;
void SettingPanel_createForm(void) {
Application::Run(gcnew SettingPanel());
}

ここでコードの変更

変更後(SettingPanel.h)

文字列はC#のマネージドコード上の形式と,アンマネージメモリ上の形式が異なりますので若干面倒です.

#pragma endregion

private: System::Void countUpButton_Click(System::Object^ sender, System::EventArgs^ e) {
}
private: System::Void sendButton_Click(System::Object^ sender, System::EventArgs^ e) {
IntPtr ptr = Marshal::StringToHGlobalAnsi(this->textBox1->Text); //テキストボックスの文字をアンマネージメモリに移動し,さらにANSI形式に変換します.
stringBuffer = static_cast<const char*>(ptr.ToPointer()); //んで代入.
}
};

RTコンポーネント本体からもstringBufferを参照できます.

変更後(PeriodicConsoleOut.cpp内,onExecuteメソッド)

#include <string>

extern std::string stringBuffer; //外部変数にアクセスするために,変数名を宣言します.

RTC::ReturnCode_t PeriodicConsoleOut::onExecute(RTC::UniqueId ec_id)
{
std::cout << “String = ” << stringBuffer <<
std::endl;
//このように直接アクセスできます.
return RTC::RTC_OK;
}

逆にマネージドC++コードから,C#のオブジェクトにアクセスできます.

変更後(SettingPanel.h)

public: int count; //メンバ変数を追加

private: System::Void countUpButton_Click(System::Object^ sender, System::EventArgs^ e) {
count++; //ボタンが押されたらインクリメント
}

private: System::Void sendButton_Click(System::Object^ sender, System::EventArgs^ e) {
IntPtr ptr = System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(this->textBox1->Text);
stringBuffer = static_cast<const char*>(ptr.ToPointer());
}

C++コード側は面倒です.今回はSettingPanelクラスのオブジェクトがグローバル変数などになっていませんから.

そこで,Formを作成する際にApplicationクラスメソッドのRunをつかいましたよね.Form本体はApplicationクラスが管理しているはずなので,そちらを参照するコードを書いてみました.

変更後(SettingPanel.cpp)

int SettingPanel_getCount() {

return ((PeriodicConsoleOut::SettingPanel^)Application::OpenForms[0])->count;

}

ApplicationクラスからOpenFormsメンバを介してFormの参照を受けとり,SettingPanelクラスへの参照にキャストしてからcountにアクセスしています.「^」はマネージドメモリに対するポインタを意味していますが,「*」の代わりだと思う程度でいいです.

んでRTコンポーネント側からはSettingPanel_getCountメソッドを介してcountパラメータを受け取ります.

変更後(PeriodicConsoleOut.cpp)内onExecute関数

#include <string>
extern std::string stringBuffer;
int SettingPanel_getCount(void); //SettingPanel.cpp内のSettingPanel_getCount関数にアクセスするために関数名を宣言します.
RTC::ReturnCode_t PeriodicConsoleOut::onExecute(RTC::UniqueId ec_id)
{
std::cout << “Text = ” << stringBuffer <<
std::endl;
std::cout << “Count = ” << SettingPanel_getCount()
<< std::endl; //関数を呼び出せばcountの値が返ってきます.

return RTC::RTC_OK;

}

rrtc.conf

これまでどおりでよろしくです.

実行

コンポーネントをアクティブ化すれば,ボタンを押すと変更がコンソール出力に反映されているのがわかると思います.

https://github.com/ysuga/GUISampleRTCs


Get Adobe Flash playerPlugin by wpburn.com wordpress themes