MFC 自定义子线程新建对话框的数据传输问题 -- 以及由此对MFC的一些思考
2016-11-16 17:59
956 查看
MFC是很老的技术了,但在工控领域,还是有优势的。只是其中一些技术比较隐蔽,不能想当然。
废话少说,上菜~~
一个简单而常用的工控架构: 一个主对话框,对话框中有一个编辑控件输入, 和一个OK按钮控件。此处省略菜单,各种特殊事件响应,不在此讨论。如下图:
故事开始,左键点击OK按钮,后台子线程开始运行。子线程运行过程中,弹出一个非模态对话框,用于一部分信息输入。如下:
关键点来了:弹出的子对话框 pDlgOption 中的 combobox 控件 m_combo_x,需要根据主对话框的输入进行初始化以及读取操作。于是我想当然的这么干:
UINT ThreadFunc_TCS_SPOTFIRE(LPVOID lpParam)
{
CDlgTCSSpotfire* pDlg = (CDlgTCSSpotfire*) lpParam; //main dialog
CDlgTCSOption pDlgOption; // modeless input dialog
if(pDlgOption.DoModal() == IDOK){
CString combo_info;
pDlgOption.m_combo_x.GetWindowTextA(combo_info);
}
::PostMessage(pDlg->GetSafeHwnd(), TCS_SPOTFIRE_DATA_HANDLE_END, NULL, NULL); //
return TRUE;
}
很不幸,编译通过,但是运行时错误。问题在于这句:
pDlgOption.m_combo_x.GetWindowTextA(combo_info);
子线程表示,在我的管辖范围,读写访问你的控件是违法的。
解决之道,直接来不行,可以绕个道。
1. 先在子对话框的类中声明需要传输的数据。如定义一个 vector 等等,把需要对子对话框进行的操作信息放到里面。
2. 在子线程里面对子对话框的类数据成员传数据,如上一部定义的 vector,当然必须是public的。
3. 以上完成后,再调用 DoModal()
4. 最后对子对话框控件的操作,在它的类中完成,如重载 OnInitDialog(),OnBnClickOk() 等等。
代码如下:
UINT ThreadFunc_TCS_SPOTFIRE(LPVOID lpParam)
{
CDlgTCSSpotfire* pDlg = (CDlgTCSSpotfire*) lpParam; //main dialog
CDlgTCSOption pDlgOption; // modeless input dialog
pDlgOption.testno_vec.clear();
for(vector<string>::iterator it = log_data.test_vec.begin(); it != log_data.test_vec.end(); ++it){
pDlgOption.testno_vec.push_back(*it);
}
if(pDlgOption.DoModal() == IDOK){
}
::PostMessage(pDlg->GetSafeHwnd(), TCS_SPOTFIRE_DATA_HANDLE_END, NULL, NULL); //
return TRUE;
}
BOOL CDlgTCSOption::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
for(vector<string>::iterator it = testno_vec.begin(); it != testno_vec.end(); ++it){
m_combo_x.AddString((*it).c_str());
}
m_combo_x.SetCurSel(0);
UpdateData(FALSE);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
小小思考:对话框虽然在子线程中声明定义,但是对话框运行时有自己的线程,它的控件部分会被自己的线程绑定,不能在子线程中访问控件,否则会出现两个线程同时操作一个控件的问题。然而对话框的非控件数据成员没有被绑定,仍然可以被声明对话框的线程调用。
但是,在主对话框的线程中,访问它的子对话框控件是没问题的。猜想是,子对话框的线程会自动 assign 到 主对话框中。
这是MFC定义各类对象,相互间的权限问题。估计是安全考虑。这是需要在 MFC 或者 C++ 编程中需要注意的。
废话少说,上菜~~
一个简单而常用的工控架构: 一个主对话框,对话框中有一个编辑控件输入, 和一个OK按钮控件。此处省略菜单,各种特殊事件响应,不在此讨论。如下图:
故事开始,左键点击OK按钮,后台子线程开始运行。子线程运行过程中,弹出一个非模态对话框,用于一部分信息输入。如下:
关键点来了:弹出的子对话框 pDlgOption 中的 combobox 控件 m_combo_x,需要根据主对话框的输入进行初始化以及读取操作。于是我想当然的这么干:
UINT ThreadFunc_TCS_SPOTFIRE(LPVOID lpParam)
{
CDlgTCSSpotfire* pDlg = (CDlgTCSSpotfire*) lpParam; //main dialog
CDlgTCSOption pDlgOption; // modeless input dialog
if(pDlgOption.DoModal() == IDOK){
CString combo_info;
pDlgOption.m_combo_x.GetWindowTextA(combo_info);
}
::PostMessage(pDlg->GetSafeHwnd(), TCS_SPOTFIRE_DATA_HANDLE_END, NULL, NULL); //
return TRUE;
}
很不幸,编译通过,但是运行时错误。问题在于这句:
pDlgOption.m_combo_x.GetWindowTextA(combo_info);
子线程表示,在我的管辖范围,读写访问你的控件是违法的。
解决之道,直接来不行,可以绕个道。
1. 先在子对话框的类中声明需要传输的数据。如定义一个 vector 等等,把需要对子对话框进行的操作信息放到里面。
2. 在子线程里面对子对话框的类数据成员传数据,如上一部定义的 vector,当然必须是public的。
3. 以上完成后,再调用 DoModal()
4. 最后对子对话框控件的操作,在它的类中完成,如重载 OnInitDialog(),OnBnClickOk() 等等。
代码如下:
UINT ThreadFunc_TCS_SPOTFIRE(LPVOID lpParam)
{
CDlgTCSSpotfire* pDlg = (CDlgTCSSpotfire*) lpParam; //main dialog
CDlgTCSOption pDlgOption; // modeless input dialog
pDlgOption.testno_vec.clear();
for(vector<string>::iterator it = log_data.test_vec.begin(); it != log_data.test_vec.end(); ++it){
pDlgOption.testno_vec.push_back(*it);
}
if(pDlgOption.DoModal() == IDOK){
}
::PostMessage(pDlg->GetSafeHwnd(), TCS_SPOTFIRE_DATA_HANDLE_END, NULL, NULL); //
return TRUE;
}
BOOL CDlgTCSOption::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
for(vector<string>::iterator it = testno_vec.begin(); it != testno_vec.end(); ++it){
m_combo_x.AddString((*it).c_str());
}
m_combo_x.SetCurSel(0);
UpdateData(FALSE);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
小小思考:对话框虽然在子线程中声明定义,但是对话框运行时有自己的线程,它的控件部分会被自己的线程绑定,不能在子线程中访问控件,否则会出现两个线程同时操作一个控件的问题。然而对话框的非控件数据成员没有被绑定,仍然可以被声明对话框的线程调用。
但是,在主对话框的线程中,访问它的子对话框控件是没问题的。猜想是,子对话框的线程会自动 assign 到 主对话框中。
这是MFC定义各类对象,相互间的权限问题。估计是安全考虑。这是需要在 MFC 或者 C++ 编程中需要注意的。
相关文章推荐
- 工作线程调用sendmessage()向主对话框发送自定义消息遇到的问题以及解决
- 使用redis缓存数据需要注意的问题以及个人的一些思考和理解
- 使用redis缓存数据需要注意的问题以及个人的一些思考和理解
- 使用redis缓存数据需要注意的问题以及个人的一些思考和理解
- ~ 使用redis缓存数据需要注意的问题以及个人的一些思考和理解
- mfc父对话框调出子对话框显示数据的问题
- PHP中如何保持SESSION以及由此引发的一些思考
- ajax中文数据传输乱码问题以及zend framework escape()调用
- 关于C++和C#的自定义数据类型转换的一些思考
- 用JSON做数据传输格式中的一些问题总结
- MFC——基本控件数据绑定,新建对话框
- Java并发编程之——原子变量(解决一些线程共享数据问题)
- mfc父对话框调出子对话框显示数据的问题
- 对LMAX架构以及Event Sourcing模式的一些新思考和问题的记录
- 转:PHP中如何保持SESSION以及由此引发的一些思考
- 针对stm32 DMA传输AD数据,在完成中断后如何复位的问题的思考
- InstallShield自定义对话框以及问题
- PHP保持SESSION问题以及由SESSION性能引发的一些思考
- 用JSON做数据传输格式中的一些问题总结
- mina自定义编解码器接收处理byte数组(同时解决数据传输中的粘包、缺包问题)