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;

}

这样就完成了在线程中操作界面的工作。

注意:

  1. 我们也可以使用继承CwinThread的类,然后在消息映射中用

ON_THREAD_MESSAGE来处理往线程中发送的消息。

2.  在线程中往主线程PostMessage发送数据的时候,一定要保证数据在主线程使用之前是存在的。Sleep(1000);是为了保证让主线程先处理到str。否则,执行完ThreadStart函数后,str自动销毁了,然后在外面访问这个已经销毁的指针是非常危险的。

我们可以通过另外一种方法来解决。

  1. 定义消息处理函数和SetWindowLong返回值

static LRESULT CALLBACK PluginWinProc(HWND, UINT, WPARAM, LPARAM);

long   OldProc;

  1. 在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在线程中操作界面的更多相关文章

  1. VC线程中操作控件,引起程序卡死的问题。

    [问题还原] 线程中操作控件,具体为控制一个按键的使能,使能后结束线程. 主程序中有一个死循环,等待线程结束. 然后,就没有然后了-- [解决方案] 在主程序死循环中,如果检测到界面消息,优先处理掉.

  2. delphi 线程教学第二节:在线程时空中操作界面(UI)

    第二节:在线程时空中操作界面(UI)   1.为什么要用 TThread ?   TThread 基于操作系统的线程函数封装,隐藏了诸多繁琐的细节. 适合于大部分情况多线程任务的实现.这个理由足够了吧 ...

  3. android4.0以上访问网络不能在主线程中进行以及在线程中操作UI的解决方法

    MONO 调用一个线程操作UI 然后报Only the original thread that created a view hierarchy can touch its views.错误 goo ...

  4. Android中进程与线程及如何在子线程中操作UI线程

    1. Android进程 一个应用程序被启动时,系统默认创建执行一个叫做"main"的线程.这个线程也是你的应用与界面工具包(android.widget和android.view ...

  5. Android--Handler的用法:在子线程中更新界面

    本文主要介绍Android的Handler的用法.Handler能够发送Messsage和Runnable对象到与其相关联的线程的消息队列. 每一个Handler对象与创建它的线程相关联.而且每一个H ...

  6. android UI 操作 不要在子线程中操作UI

    不管是android ,还是 ios ,请不要在子线程中操作UI,有时有些崩溃,从报错上看不出什么原因,就有可能是子线程操作了UI:切记,切记! 请放在主线程例: activity.runOnUiTh ...

  7. EXC_BAD_ACCESS(code=2,address=0xcc 异常解决 及 建议不要在子线程中刷新界面

    iOS 上不建议在非主线程进行UI操作,在非主线程进行UI操作有很大几率会导致程序崩溃,或者出现预期之外的效果. 我开始不知道这一点,在子线程中进行了弹窗操作,结果程序就出问题了! 报的错误是(EXC ...

  8. 为什么在非UI线程中操作UI的改变失不安全的

    因为你如果允许在非UI线程更新操作UI的东西,那我再另一个非UI线程也可以更新这个Ui的东西 这样就会有冲突,比如你的线程刚好跑到修改UI这里,我的另一个UI也有可能跑到这里,所以这样导致线程不安全. ...

  9. c#子线程线程中操作窗体更新的报错

    用 在执行上传时,由于操作较长窗体界面卡住,于是用task解决 Task t1 = new Task(manage.UploadData); t1.Start(); 结果不卡了,程序也传完了,运行到更 ...

随机推荐

  1. 使用Let's Encrypted HPPTS你的网站

    1.前言 最近,有同事咨询我,怎么样使用Let's Encrypted部署数字证书,于是,结合自己之前的实践,简单总结下. 2.HTTPS的优势 什么加密,防篡改,防广告植入什么的,这个就不多说了.这 ...

  2. Ex 6_14 布料剪裁问题_第八次作业

    子问题定义: 定义p[i][j]为布料宽为i,高为j的最优产出,每次剪下一块布料,剩余布料最多形成三块矩阵面料.每次剪裁会有两种情况,水平切割布料,其次是将布料旋转90度后在切割布料. 递归关系: 初 ...

  3. Day5------------系统启动流程

    一.引导顺序 BIOS--------------------->MBR-------------------->boot loader------------------------&g ...

  4. vue scoped 穿透_vue 修改内部组件样式问题

    何为scoped? 在vue文件中的style标签上,有一个特殊的属性:scoped.当一个style标签拥有scoped属性时,它的CSS样式就只能作用于当前的组件,也就是说,该样式只能适用于当前组 ...

  5. Redis Windows上下载安装

    其它的默认就可. public class RedisTest { public static void main(String[] args) { Jedis jedis = RedisPool.g ...

  6. python 全栈开发,Day99(作业讲解,DRF版本,DRF分页,DRF序列化进阶)

    昨日内容回顾 1. 为什么要做前后端分离? - 前后端交给不同的人来编写,职责划分明确. - API (IOS,安卓,PC,微信小程序...) - vue.js等框架编写前端时,会比之前写jQuery ...

  7. python 全栈开发,Day88(csrf_exempt,ES6 快速入门,Vue)

    BBS项目内容回顾 1. 登陆页面 1. 验证码 1. PIL(Pillow) 2. io 2. ORM 1. 增删改查 3. AJAX $.ajax({ url: '', type: '', dat ...

  8. CentOS6.8安装360 pika

    1.安装依赖包 yum install snappy-devel bz2 libzip-dev libsnappy-dev libprotobuf-dev libevent-dev protobuf- ...

  9. Spring启动研究2.AbstractApplicationContext.obtainFreshBeanFactory()研究

    据说这个方法里面调用了loadBeanDefinitions,据说很重要,并且跟我感兴趣的标签解析有关,所以仔细看看 obtainFreshBeanFactory()这个方法在AbstractAppl ...

  10. 怎么在项目中使用前端包管理器bower和构建工具gulp

    下面以WeUI(微信官方网页开发样式库)介绍一下,怎么把WeUi引入到自己的项目中,我的开发环境Visual Studio 2012,当然了Visual Studio 2015对此已有了更好的支持(h ...