一、多线程设计
1、线程创建
HANDLE m_hThreadControl;
m_hThreadControl = ::CreateThread(NULL, 0, ThreadControl, (LPVOID)this, 0 ,0);
注:线程函数是回调函数,因此必须是静态函数。
m_hThreadControl用来保存线程句柄。
2、线程函数定义
DWORD WINAPI 类名::ThreadControl(LPVOID lpData)
{
类名 *This = reinterpret_cast<类名 *>(lpData);
}
注:This 是传过来的对象指针,必须经过强制转换才能使用;
WINAPI #define WINAPI__stdcall 定义了函数参数入栈的顺序。
3、线程终止
其中用线程函数的return返回, 而终止线程是最安全的,
在线程函数return返回后, 会清理函数内申请的类对象。
注:不要使用ExitThread()函数,会造成内存泄露。
4、线程数据传输
遇到问题:
在线程外可以正常获取图像指针,但在线程里通过完全相同的
方式却无法正常获取。
解决途径:
可以在将在线程外正常获取的图像指针单独用一个成员变量保存起来,在
线程中直接调用该变量就可以了,不需要再重新去获取。
问题关键:
AfxGetMainWnd()函数获取的是当前线程的窗口指针,如果在主线程里调用,
则返回主线程的窗口指针,如果是在工作线程里调用,则返回工作线程的窗口指针。
这个函数在线程中使用是有问题的,应使用AfxGetApp()->GetMainWnd()。
5、线程互斥
有时候为了线程函数中某些函数的不间断执行,需要用到互斥锁。
比如:
HANDLE hMutex = NULL;
WaitForSingleObject(hMutex);
m_Cameral1.SingleGrab(&m_ImageThread);
ReleaseMutex(hMutex);
6、临界区
临界区(Critical Section)是一段供线程独占式访问的代码,也就是说若有一线程正在访问该代码段,其它线程想要访问,
只能等待当前线程离开该代码段方可进入,这样保证了线程安全。他工作于用户级(相对于内核级),在Window系统中
CRITICAL_SECTION实现临界区相关机制。
临界区使用相关函数:
void InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection) // 初始化临界区
void EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) // 进入临界区
void LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection) // 离开临界区
void DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection) // 释放临界区资源
7、事件
1)创建事件
HANDLE
g_Event;
g_Event=CreateEvent(NULL,FALSE,FALSE,NULL);
2)等待事件WaitForSingleObject(g_Event,INFINITE);
3)触发事件
SetEvent(g_Event);
4)销毁事件
CloseHandle(g_Event);
二、类之间变量访问
1、AfxGetMainWnd()函数用法
使用AfxGetMainWnd函数获取MFC程序中的主框架类指针是一个常用作法。
就是获得应用程序主窗口的指针,AfxGetMainWnd()-> m_hWnd是主窗口的句柄。
注:返回类型需要做相应强制转换。
CMyParentDlg *pMPD = (CMyParentDlg*)this->GetParent(); //获取父窗口指针
三、控件使用
1、radio button使用
数据交互
DDX_Radio(pDX,IDC_RADIO,m_Radio);
数据刷新
UpdateData()用来刷新数据的。要接受用户的输入就 true,要输出结果给用户就 false。
2、tab control
注意子对话框与父对话框的关联
父对话框IDC_TAB1
子对话框IDD_DIALOG1,对象m_page1
m_page1.Create(IDD_DIALOG1,GetDlgItem(IDC_TAB1));
动态创建的问题:tab control可以新建多个子标签,可以通过另一窗口点击添加,
但是要注意如果完全在另一窗口添加,新建子窗口会以这个窗口为基准显示,造成
子标签没出现在你希望出现的位置。
解决途径:可以在原父窗口事先创建所有的子窗口,但不显示出来;当在另一窗口
添加子窗口,只添加标签就可以了,点击标签切换,先前新建的子窗口就可以显示
出来。
3、消息
自定义消息宏
#defineWM_TOOL_DOUBLE_CLICKED WM_USER+1
发消息给DlgSet对话框
GetDlgSet()->SendMessage(WM_TOOL_DOUBLE_CLICKED,WPARAM(this),LPAPAM(&m_iCameraNum));
消息映射
ON_MESSAGE(WM_TOOL_DOUBLE_CLICKED, OnDoubleClickedTool);
消息响应函数
LRESULT CDlgSet::OnDoubleClickedTool(WPARAM wParam, LPAPAM lParam)
4、下拉框控件CComboBox
CComboBox m_ComboNICList;
数据关联DDX_Control(pDX, IDC_COMBO_NICLIST,m_ComboNICList);
列表信息添加m_ComboNICList.AddString(InfoBuffer);
选择项数值获取m_ComboNICList.GetCurSel();
5、点击按键进不了响应函数
问题:添加按键,设置断点运行发现点击按键进不了响应函数
原因:检查发现消息映射中,控件ID同号不同名
6、列表控件CListCtrl
添加控件变量
CListCtrl m_CListToolItem;
为列表视图控件添加全行选中和栅格风格
m_CListToolItem.SetExtendedStyle(m_CListToolItem.SetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
获取列表视图控件的位置和大小
m_CListToolItem.GetClientRect(&rect);
为列表视图控件添加两列
m_CListToolItem.InsertColumn(0, _T("工具ID"), LVCFMT_CENTER, rect.Width()/4, 0);
m_CListToolItem.InsertColumn(1, _T("工具名称"), LVCFMT_CENTER, rect.Width()/4*3, 1);
添加NM_CLICK消息响应
NMLISTVIEW *pNMListView = (NMLISTVIEW *) pNMHDR;
if(-1 != pNMListView->iTtem) //判断有无选中项
{
}
插入列表项
m_CListToolItem.InsertItem(0, _T("0"));
m_CListToolItem.SetItemText(0, 1, _T("检测结果"));
m_CListToolItem.InsertItem(1, _T("1"));
m_CListToolItem.SetItemText(1, 1, _T("运行时间"));