• ベストアンサー

VC++ スレッドからDoModalへ

いまさらですがVC++6.0でつまづいています MFCです AdlgクラスのダイアログのOnButtonA() からXXXスレッドを起動し そのXXXスレッドではcountを+1しつづけます。 そして別のダイアログ DDD10をDoModalで起動しそのDDD10 内のTextBoxの値にcount値を反映させて表示しようとしました 下記ソース内のAfxMessageBox(tmp);ではcount値は 更新されますが DDD10ダイアログ内のテキストボックス の値が変更されません m_gui_xfr_totalはDDD10のテキストボックスにつけた メンバー名です どなたかアドバイスをお願いします void ADlg::OnButtonA() { DDD10 dlg10 ; CWinThread *pThread = AfxBeginThread(XXX_thread_entry,(LPVOID *)this); dlg10.DoModal() ; } void XXX_Thread(){ CString tmp; unsigned int count=0; DDD10 dlg10; while(1){ count++; tmp.Format("%d",count); dlg10.m_gui_xfr_total.Format(tmp); AfxMessageBox(tmp); Sleep(1000); } }

質問者が選んだベストアンサー

  • ベストアンサー
  • takoashi
  • ベストアンサー率39% (21/53)
回答No.2

スレッドごしのコントロールアクセスには制限がありますなんて、いうより、 OnButtonAで定義されている dlg10 と スレッド内で定義されている  dlg10 は違うオブジェクトですよ。

C_is_Best
質問者

お礼

redfox63さんへの補足に書きましたように おかげさまでうまくいきました 今回はオブジェクトが違うとの指摘が 助かりました

C_is_Best
質問者

補足

オブジェトの基本が理解できてませんでした 指摘ありがとうございます。 ということでまずはスレッドごしに挑戦する前に 以下のようにDDD10からスレッドを起動して DDD10のテキストボックスの表示が変化するかを 見てみました。 DDD10のテキストボックスm_gui_xfr_totalの表示が 1秒毎に1→2→3→4→5と変化するのを期待した のですが 1 と表示されたままで 変化しません でした。 ご指摘願います DDD10::DDD10(CWnd* pParent /*=NULL*/) : CDialog(DDD10::IDD, pParent) { CString tmp; unsigned int count=0; //{{AFX_DATA_INIT(DDD10) m_gui_xfr_total = _T("12345678"); //}}AFX_DATA_INIT CWinThread *pThread = AfxBeginThread(XFR_Monitor_thread_entry,(LPVOID *)this); } public: static UINT XFR_Monitor_thread_entry(LPVOID v) { ((DDD10*)v)->XFR_Monitor_Thread(); return 0; } class DDD10 : public CDialog { void XFR_Monitor_Thread(){ CString tmp; unsigned int count=0; while(1){ count++; m_gui_xfr_total.Format("%d",count); if(count==5)break; Sleep(1000); } }

その他の回答 (4)

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.5

クラス間でもやり方は一緒です まずスレッドに渡すデータの構造体を定義します 今回の場合カウント用の変数とダイアログのウィンドウハンドルがあれば十分でしょう メッセージのやり取りにウィンドウのハンドルが必要になるため DDD10クラスからスレッド起こす必要があるでしょう typdef struct tagData {   int nData;   HWND hWnd; } TAGDATA, *LPTAGDATA; DDD10クラスに TAGDATA型のメンバー変数を準備 TAGDATA m_TagData; スレッドとのメッセージを定義します static UINT msgCount = RegisterWindowMessage( "MyCount" ); DDD10クラスのメッセージマップに ON_REGISTERES_MESSAGE( msgCount, OnMyMessage ) を追加 ハンドラを定義 afx_msg LRESULT DDD10::OnMyMessage( WPARAM wParam, LPARAM lParam) {   // wParamに次に表示するデータが設定されている   m_gui_xfr_total.Format("%d",(int)wParam);   UpdateData( FALSE ); } スレッドのメインルーチンを void XFR_Monitor_Thread(LPVOID pPram){   unsigned int count=0;   HWND hWnd = ((LPTAGDATA)pParam)->hWnd;   // カウントの初期値があるなら   // count = ((LPTAGDATA)pParam)->nData;   while(1){     count++;     PostMessage( hWnd, msgcount, count, 0 );     if(count==5)break;     Sleep(1000);   } } スレッド起動は DDDクラスの OnInitDialogあたりで m_TagData.nData = 0; m_TagData.hWnd = this->m_hWnd; AfxBeginThread( XFR_Monitor_Thread, &m_TagData ); といった具合でしょう

C_is_Best
質問者

お礼

初心者にとってはかなりの難関です 教えて頂いた内容をすこしづつ理解しながら 実験していきたいと思います 具体的なソースでの回答ありがとうございます

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.4

基本的にやり方が違いますよ ワーカスレッドとメインスレッドとのやり取りには 1) RegisterWindowMessageなどで共通のメッセージを定義しておいて 2) スレッド側からPostMessageでwParamyやlParamでデータを送信 3) 受け側のダイアログのメッセージマップにRegisterWindowMessageで設定したメッセージのマクロとハンドラを実装 4) ハンドラ内で クラス変数(CString型)の内容を送信データから構築 UpdateDataで変数とコントロールの内容を更新 といた具合でしょう DoDataExchangeの中でスレッド起動はうまくないと思いますよ DoDataExchangeは双方向で呼ばれます 変数をコントロールへと、コントロールから変数への2種類です スレッドの起動は別の適切な関数に移動しましょう ボタンのクリックで起動するとか、ダイアログのインスタンス化する際のコンストラクタでやるとか

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.3

DDXマクロが動作するようなコードが必要ですよ コントロールに割り当てた変数とコントロールの表示内容を整合させるために DDX_TextやDDX_Controlなどで行っているとおもいます CString型のクラスメンバーにデータを設定したなら UpdateDataを呼び出して DoDataExchangeが呼ばれるようにします 第一歩としてはダイアログの中のボタンを押したらテキストボックスの数値がカウントアップする といった物を作成してみましょう

C_is_Best
質問者

お礼

ありがとうございます 以下のようにスレッド起動処理をDoDataExchangeへ移動 void DDD10::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(DDD10) DDX_Text(pDX, IDC_EDIT1, m_gui_xfr_total); //}}AFX_DATA_MAP CWinThread *pThread = AfxBeginThread(XFR_Monitor_thread_entry,(LPVOID *)this); } そして class DDD10 : public CDialog { void XFR_Monitor_Thread(){ CString tmp; unsigned int count=0; xfr_test_end = 0; while(1){ if (xfr_test_end == 1)break; count++; m_gui_xfr_total.Format("%d",count); SetDlgItemText(IDC_EDIT1, m_gui_xfr_total); Sleep(1000); } } のようにSetDlgItemTextを利用しましたらうまくcount値が 1秒毎に変化するようになりました

C_is_Best
質問者

補足

それぞれのダイアログ内でのデータをテキストボックスへ 表示はできるようになり喜んでいたのですが 次なる難関が待ち構えておりました。 クラスの異なるスレッド間でのデータの受け渡しに難航しています 手法について ご教授願います

  • penta1331
  • ベストアンサー率64% (16/25)
回答No.1

>> dlg10.m_gui_xfr_total.Format(tmp); dlg10.m_gui_xfr_total.SetWindowText(tmp); じゃなくて?

関連するQ&A