質問者
Invokeを使用した別スレッドからのコントロール操作

質問
-
お世話になっております。
前に別スレッドからの非静的関数を使用したコントロール操作について質問し、上手くいったのですがInvokeを使用した処理にしようとしますと実行時にエラーとなってしまいます。
おそらくDelegate関数の第一パラメータとして元のFormを渡せればいいのだと思うのですがやり方が分かりません。
お手数ですがお分かりになる方がいらっしゃいましたらご教授ください。
#pragma once
namespace TestMonitor
{
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace System::Threading;public __gc class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent();
}・
・
・public:
__delegate void TestttDelegate(int);void worker(void)
{
Testtt(0);
}void Testtt(int a)
{
if (InvokeRequired)
{
// 別スレッドから呼び出された場合
Invoke(new TestttDelegate(0,Testtt)); ←ここでWindowsエラー発生
return;
}
this->text_Data01->Text = "test";
}private: System::Void button_Start_Click(System::Object * sender, System::EventArgs * e)
{
if(0 == button_Start->get_Text()->CompareTo("START"))
{
button_Start->set_Text("STOP");Thread* oThread = new Thread(new ThreadStart(this, &Form1::worker));
oThread->Start();
}
else
{
button_Start->set_Text("START");
}
}
};
}
すべての返信
-
再度のご回答ありがとうございます。
ご提示の方法でやってみました。
まず変数argsのところでコンパイルがエラーとなってしまいましたので関数の方を引数無しに変更し、下記のようなコードになりました。
this->Invoke(new TestttDelegate(this, Testtt));
これでコンパイルは通ったので実行してみましたところ上記の行の実行後にプログラムが一切のコントロールを受け付けなくなってしまいました。
デバッガ上で確認しましたところ、どうも「this」の内容が無効なようなのです。
元のスレッド開始時点でのthisの値をグローバルな変数にでも入れておいて渡せばいいのか?と思っているのですがthisの型が分からないので困っております。
-
>デバッガ上で確認しましたところ、どうも「this」の内容が無効なようなのです。
その解釈は間違っているんじないかなぁ。
thisが不正だったら Invoke すら呼べないかと。
>関数の方を引数無しに変更
はどこを変更しましたか?
あと、ためしに
this->Invoke(new TestttDelegate(this, &Form1::Testtt));
でもだめかやってみてください。
ちなみに
>まず変数argsのところでコンパイルがエラーとなってしまいましたので
はどのようなエラーが出ましたか?
>Object* args[] = new Object[1];
は
Object* args[] = new Object*[1];
だったかも。 -
>>関数の方を引数無しに変更
>はどこを変更しましたか?
下記のようにしました。public:
__delegate void TestttDelegate(void);←ここvoid worker(void)
{
Testtt();←ここ
}void Testtt(void)←ここ
{
if (InvokeRequired)
{
// 別スレッドから呼び出された場合
Invoke(new TestttDelegate(this,&Form1::Testtt)); ←ここでWindowsエラー発生
return;
}
this->text_Data01->Text = "test";
}>this->Invoke(new TestttDelegate(this, &Form1::Testtt));
>でもだめかやってみてください。結果は同じでした、実行時にコントロール不可になります。
>>まず変数argsのところでコンパイルがエラーとなってしまいましたので
>はどのようなエラーが出ましたか?
>
>>Object* args[] = new Object[1];
>は
>Object* args[] = new Object*[1];
>だったかも。エラーは「error C2691: 'System::Object' : __gc 配列の要素の型が正しくありません。」が出力されました。
new Object*[1]にしましたところコンパイルは通りましたので引数付に戻し下記のようなコードになりましたが実行時にコントロール不可になるのは同じです。public:
__delegate void TestttDelegate(int a);void worker(void)
{
Testtt(0);
}void Testtt(int a)
{
if (InvokeRequired)
{
Object* args[] = new Object*[1];
args[0] = __box(a);
// 別スレッドから呼び出された場合
this->Invoke(new TestttDelegate(this,&Form1::Testtt),args); ←ここ実行後以降だんまり
return;
}
this->text_Data01->Text = "test";
}private: System::Void button_Start_Click(System::Object * sender, System::EventArgs * e)
{
if(0 == button_Start->get_Text()->CompareTo("START"))
{
button_Start->set_Text("STOP");Thread* oThread = new Thread(new ThreadStart(this, &Form1::worker));
oThread->Start();
}
else
{
button_Start->set_Text("START");
}
} -
VS2005の環境しかないので、/clr:oldSyntaxでコンパイルして試してみたコードです。
問題なく動いているようですが。
準備:Form1上に textBox1 と button1 を用意
ボタンを押すと現在時間を1秒間隔で表示していくシンプルなものです。private: Thread* thread; // ボタンクリックイベント System::Void button1_Click(System::Object* sender, System::EventArgs* e) { if (this->thread) this->thread->Abort(); this->thread = new Thread(new ThreadStart(this, &Form1::Worker)); this->thread->Start(); } // フォームClosingイベント System::Void Form1_Closing(System::Object* sender, System::ComponentModel::CancelEventArgs* e) { if (this->thread) this->thread->Abort(); } void Worker() { while (true) { if (this->InvokeRequired) { Object* args[] = new Object*[1]; args[0] = DateTime::Now.ToString("HH:mm:ss"); this->Invoke( new DisplayTextDelegate(this, &Form1::DisplayText), args); } else this->DisplayText(DateTime::Now.ToString("HH:mm:ss")); Thread::Sleep(1000); } } __delegate void DisplayTextDelegate(String*); void DisplayText(String* text) { this->textBox1->Text = text; }