VC在线程中操作界面
http://blog.csdn.net/tingsking18/article/details/4399199
多线程是我们在编程中经常遇到的问题,线程执行完后往往要把执行的结果传给主线程,但是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线程中操作控件,引起程序卡死的问题。
[问题还原] 线程中操作控件,具体为控制一个按键的使能,使能后结束线程. 主程序中有一个死循环,等待线程结束. 然后,就没有然后了-- [解决方案] 在主程序死循环中,如果检测到界面消息,优先处理掉.
- delphi 线程教学第二节:在线程时空中操作界面(UI)
第二节:在线程时空中操作界面(UI) 1.为什么要用 TThread ? TThread 基于操作系统的线程函数封装,隐藏了诸多繁琐的细节. 适合于大部分情况多线程任务的实现.这个理由足够了吧 ...
- android4.0以上访问网络不能在主线程中进行以及在线程中操作UI的解决方法
MONO 调用一个线程操作UI 然后报Only the original thread that created a view hierarchy can touch its views.错误 goo ...
- Android中进程与线程及如何在子线程中操作UI线程
1. Android进程 一个应用程序被启动时,系统默认创建执行一个叫做"main"的线程.这个线程也是你的应用与界面工具包(android.widget和android.view ...
- Android--Handler的用法:在子线程中更新界面
本文主要介绍Android的Handler的用法.Handler能够发送Messsage和Runnable对象到与其相关联的线程的消息队列. 每一个Handler对象与创建它的线程相关联.而且每一个H ...
- android UI 操作 不要在子线程中操作UI
不管是android ,还是 ios ,请不要在子线程中操作UI,有时有些崩溃,从报错上看不出什么原因,就有可能是子线程操作了UI:切记,切记! 请放在主线程例: activity.runOnUiTh ...
- EXC_BAD_ACCESS(code=2,address=0xcc 异常解决 及 建议不要在子线程中刷新界面
iOS 上不建议在非主线程进行UI操作,在非主线程进行UI操作有很大几率会导致程序崩溃,或者出现预期之外的效果. 我开始不知道这一点,在子线程中进行了弹窗操作,结果程序就出问题了! 报的错误是(EXC ...
- 为什么在非UI线程中操作UI的改变失不安全的
因为你如果允许在非UI线程更新操作UI的东西,那我再另一个非UI线程也可以更新这个Ui的东西 这样就会有冲突,比如你的线程刚好跑到修改UI这里,我的另一个UI也有可能跑到这里,所以这样导致线程不安全. ...
- c#子线程线程中操作窗体更新的报错
用 在执行上传时,由于操作较长窗体界面卡住,于是用task解决 Task t1 = new Task(manage.UploadData); t1.Start(); 结果不卡了,程序也传完了,运行到更 ...
随机推荐
- Eclipse开发时出现HTTP 403 错误(禁止访问)的解决方法
1. 打开项目的页面如下: 可以从tomcat log中发现Connection has been abandoned PooledConnection和Too many connections. 2 ...
- javaMelody监控javaWeb程序性能
JavaMelody应用监控使用指南 原文:<JavaMelody应用监控使用指南> 前言 本文参考JavaMelody的UserGuide编写,部分文字均来自文档,添加有个人理解.并进行 ...
- OCM_第十五天课程:Section6 —》数据库性能调优 _SQL 访问建议 /SQL 性能分析器/配置基线模板/SQL 执行计划管理/实例限制
注:本文为原著(其内容来自 腾科教育培训课堂).阅读本文注意事项如下: 1:所有文章的转载请标注本文出处. 2:本文非本人不得用于商业用途.违者将承当相应法律责任. 3:该系列文章目录列表: 一:&l ...
- Spark的HA部署
一.安装JDK.Scala 二.安装zookeeper 三.安装Hadoop 四.安装Spark 1.修改spark/conf/spark-env.sh export JAVA_HOME=/usr/j ...
- laravel 中间件
创建中间件命令 php artisan make:middleware CheckLogin 执行完以上命令会在app/Http/Middleware目录下创建一个新的中间件类CheckLogin.p ...
- JavaScrit全面总结
前端技术的发展变化太快了,各种各样的框架.再变也离不开js.所以,在此把js的高级语法总结一遍. js解析和执行包括:全局和函数 一:全局预处理 <script type="te ...
- springboot2.0+dubbo整合分布式服务发布和调用
最近项目上要对以前的老项目做分布式的整改,因此我专门花了点时间研究下当前比较热门的dubbo和springboot结合使用,以前使用过dubbo,但是没有与springboot结合过,在网上查了点资料 ...
- c# 服务安装后自动启动
switch (rs) { case 1: var path = @&q ...
- MySQL_join连接
join连接 table1: table2: 笛卡尔积: 就是一个表里的记录要分别和另外一个表的记录匹配为一条记录,即如果表A有2条记录,表B也有2条记录,经过笛卡尔运算之后就应该有2*2即4条记录. ...
- Python 手动新建 Scrapy项目
# 创建项目 scrapy startproject 工程名 # 创建爬虫 scrapy genspider example example.com