VC在线程中操作界面
2014-10-23 20:42
274 查看
/article/1759184.html
多线程是我们在编程中经常遇到的问题,线程执行完后往往要把执行的结果传给主线程,但是MFC的控件不是线程安全的,所以在线程中操作界面是一件很危险的事情。所以就需要安全的方法。这一系列篇文章我将介绍VC在线程操作界面方法。问题描述:
1.界面上有两个Button m_btn1,m_btn2。m_btn创建一个线程,来操作m_btn2。
void CMyDlg::OnButton1()
{
_beginthread(ThreadStart,0,(void *)(m_btn2));
}
2.线程执行的代码如下:
void ThreadStart(void* p)
{
CButton *btn = (CButton*)(p);
btn->SetWindowText("aaaaaaa");
}
这是我们想象的代码,但是如果这样写来,是不正确的。是因为MFC窗体程序的界面控件是由主线程来控制的,由于我在新创建的线程中也操作了界面的控件,这样就同时由两个线程操作一个控件。但是这两个线程又没有进行同步。所以就发生了错误。
下面我们就通过让工作线程和主线程进行同步来解决上面的问题。
1.定义MYMSG
#define MYMSG WM_USER +200
2.线程启动的代码如下:
void CMyDlg::OnButton1()
{
_beginthread(ThreadStart,0,(void *)(this));
}
3.线程执行的代码如下:
void ThreadStart(void* p)
{
CString str = "aaaaaa";
CMyDlg *btn = (CMyDlg*)(p);
PostMessage(btn->m_hWnd,MYMSG,WPARAM(&str),NULL);
Sleep(1000);
}
4.添加消息映射
ON_MESSAGE(MYMSG,OnMsgBack)
5.添加消息映射函数的定义和实现
LRESULT OnMsgBack(WPARAM wParam,LPARAM lParam);
LRESULT CMyDlg::OnMsgBack(WPARAM wParam,LPARAM lParam)
{
CString* str = (CString*)wParam;
m_btn2.SetWindowText(*str);
return 0;
}
这样就完成了在线程中操作界面的工作。
注意:
我们也可以使用继承CwinThread的类,然后在消息映射中用
ON_THREAD_MESSAGE来处理往线程中发送的消息。
2. 在线程中往主线程PostMessage发送数据的时候,一定要保证数据在主线程使用之前是存在的。Sleep(1000);是为了保证让主线程先处理到str。否则,执行完ThreadStart函数后,str自动销毁了,然后在外面访问这个已经销毁的指针是非常危险的。
我们可以通过另外一种方法来解决。
定义消息处理函数和SetWindowLong返回值
static LRESULT CALLBACK PluginWinProc(HWND, UINT, WPARAM, LPARAM);
long OldProc;
在Button1的处理函数中创建线程
void CMyDlg::OnButton1()
{
HWND h = m_btn2.m_hWnd;
OldProc = SetWindowLong(h,GWL_WNDPROC,long(PluginWinProc));
_beginthread(ThreadStart1,0,(void *)(&m_btn2));
}
3.
void CMyDlg::OnDestroy()
{
CDialog::OnDestroy();
SetWindowLong(m_btn2.m_hWnd,GWL_WNDPROC,OldProc);
}
4.
static LRESULT CALLBACK PluginWinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case MYMSG:
{
CWnd *wnd = CWnd::FromHandle(hwnd);
wnd->SetWindowText("aaaaaaa");
}
break;
default:
break;
}
return CallWindowProc((WNDPROC)OldProc,hwnd,msg,wParam,lParam);
}
代码都非常简单。关键的是SetWindowLong这个函数,这个函数的作用是设定窗口属性。GWL_WNDPROC 为窗口过程设置新地址。下面是MSDN中关于SetWindowLong和GWL_WNDPROC的说明:
若使用SetWindowLong函数和GWL_WNDPROC索引替换窗口过程,则给定的窗口过程必须遵
循WindowProc回调函数的说明中指定的准则。
使用GWL_WNDPROC索引调用SetWindowLong函数可创建该窗口类的子类(窗口类用来创建窗
口)。应用程序不得用另一个过程的窗口产生子类。
当然要在使用完后在用SetWindowLong原来的窗口过程设置回去。使用这种方法可用于修改你无法更改代码的类,可以重写他的消息处理函数。
相关文章推荐
- VC在线程中操作界面(二)
- VC在线程中操作界面
- VC在线程中操作界面(一)
- VC在线程中操作界面
- vc++学生选课系统开发 sql语句操作数据库 学生界面模块
- VC 6.0 实现线程控制界面控件
- 在WinFrom应用中,如果使用后台线程来操作界面应调用Control.Invoke()方法
- swt在其它线程中调用界面控件的操作
- VC 调试错误,在界面推出操作时报如下错误,从新全部编译一下就可以了!
- Java等待线程终止,可用于加载数据再刷新界面等操作
- 安卓按钮响应线程中也不能直接通过JNI操作COCOS2D-X界面
- Winform跨线程操作界面的策略
- pyqt4 利用信号槽在子线程里面操作Qt界面
- C#Winform线程操作界面控件
- 为什么说android UI操作不是线程安全的 分类: Android 2014-09-23 21:08 1357人阅读 评论(0) 收藏 举报 目录(?)[+] 可能在非UI线程中刷新界面的时候,U
- C# 跨线程操作UI(界面)
- c#跨线程操作界面
- 在线程中操作界面控件
- worker线程操作界面引起的死锁
- vc 操作ado用线程完成