プロが教える店舗&オフィスのセキュリティ対策術

いまさらですが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);
}
}

A 回答 (5件)

スレッドごしのコントロールアクセスには制限がありますなんて、いうより、




OnButtonAで定義されている
dlg10



スレッド内で定義されている 
dlg10

は違うオブジェクトですよ。

この回答への補足

オブジェトの基本が理解できてませんでした
指摘ありがとうございます。

ということでまずはスレッドごしに挑戦する前に
以下のように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);
}
}

補足日時:2008/09/01 13:05
    • good
    • 0
この回答へのお礼

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

お礼日時:2008/09/01 14:58

クラス間でもやり方は一緒です


まずスレッドに渡すデータの構造体を定義します
今回の場合カウント用の変数とダイアログのウィンドウハンドルがあれば十分でしょう
メッセージのやり取りにウィンドウのハンドルが必要になるため 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 );
といった具合でしょう
    • good
    • 0
この回答へのお礼

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

お礼日時:2008/09/02 07:58

基本的にやり方が違いますよ


ワーカスレッドとメインスレッドとのやり取りには
1) RegisterWindowMessageなどで共通のメッセージを定義しておいて
2) スレッド側からPostMessageでwParamyやlParamでデータを送信
3) 受け側のダイアログのメッセージマップにRegisterWindowMessageで設定したメッセージのマクロとハンドラを実装
4) ハンドラ内で クラス変数(CString型)の内容を送信データから構築
UpdateDataで変数とコントロールの内容を更新
といた具合でしょう

DoDataExchangeの中でスレッド起動はうまくないと思いますよ
DoDataExchangeは双方向で呼ばれます
変数をコントロールへと、コントロールから変数への2種類です

スレッドの起動は別の適切な関数に移動しましょう
ボタンのクリックで起動するとか、ダイアログのインスタンス化する際のコンストラクタでやるとか
    • good
    • 0

DDXマクロが動作するようなコードが必要ですよ



コントロールに割り当てた変数とコントロールの表示内容を整合させるために
DDX_TextやDDX_Controlなどで行っているとおもいます

CString型のクラスメンバーにデータを設定したなら
UpdateDataを呼び出して DoDataExchangeが呼ばれるようにします

第一歩としてはダイアログの中のボタンを押したらテキストボックスの数値がカウントアップする
といった物を作成してみましょう

この回答への補足

それぞれのダイアログ内でのデータをテキストボックスへ
表示はできるようになり喜んでいたのですが
次なる難関が待ち構えておりました。

クラスの異なるスレッド間でのデータの受け渡しに難航しています
手法について ご教授願います

補足日時:2008/09/01 18:50
    • good
    • 0
この回答へのお礼

ありがとうございます

以下のようにスレッド起動処理を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秒毎に変化するようになりました

お礼日時:2008/09/01 14:52

>> dlg10.m_gui_xfr_total.Format(tmp);



dlg10.m_gui_xfr_total.SetWindowText(tmp);
じゃなくて?
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!