zoukankan      html  css  js  c++  java
  • MFC在子线程中创建窗口(PostMessage方法)

    1、创建子线程

    C++创建线程的方式比较多

    1)最简单易用的<thread>头文件,但是这种方法创建的子线程中无法给主线程PostMessage消息(也可能是我操作有误,总之没成功)

    2)3)4)参见VC创建线程的三种方法https://blog.csdn.net/u014568921/article/details/44262645

    第3、4种用在MFC程序中貌似也不行,多次尝试之下我用了AfxBeginThread()方法成功了

    void CMFCDLLTestDlg::OnBnClickedMessage()
    {
        // TODO: 在此添加控件通知处理程序代码
        // 启动websocket线程
        AfxBeginThread((AFX_THREADPROC)MsgThread, (VOID*)this, THREAD_PRIORITY_NORMAL, 0, 0, NULL);
    }

    我这里是在一个按钮点击事件中启动了一个websocket线程,全局线程函数MsgThread()

    2、通过自定义消息创建窗口

    在MFC程序中,在子线程中直接调用Create()方法无法创建非模态窗口,貌似子线程的循环阻塞了创建过程,所以需要用自定义消息方法通知主线程来创建

    2.1 自定义消息

    MFC自定义消息其实不难,分三个步骤

    1、定义一个消息ID

    我的程序名叫MFCDLLTestDlg,所以在MFCDLLTestDlg.cpp中定义下一个消息ID

    #define TEST_SENDMSG WM_USER+200//给消息一个ID

    2、定义消息处理函数

    消息处理函数是用来处理收到的自定义消息的,这个有两种方法,可以通过类向导添加一个自定义消息处理,或者自己手写也行,使用类向导可以直接绑定,省了第三步

    类向导方式:切换到类试图--->类向导--->消息--->添加自定义消息,然后输入自定义的消息ID和处理函数名称就好了

     手写方式和类向导一样,反正消息ID必须是自己定义的,固定WM_USER+一个数,不重复就行

    然后再头文件中声明消息处理函数,注意在对话框主类中写

    afx_msg LRESULT OnTestSendmsg(WPARAM wParam, LPARAM lParam);

    然后在cpp中定义

    LRESULT CMFCDLLTestDlg::OnTestSendmsg(WPARAM wParam, LPARAM lParam)
    {
        switch (wParam)
        {
        case TEST_SENDMSG:
            CMsgWindow * p_MsgWindow = new CMsgWindow();
            p_MsgWindow->SetSkin(MAKEINTRESOURCE(IDB_BITMAP1));
            //p_MsgWindow->SetSkin(MAKEINTRESOURCE(IDB_BITMAP2));
            //p_MsgWindow->SetSkin(MAKEINTRESOURCE(IDB_BITMAP3));
    
            CString *cmsg = (CString *)lParam;
    
            if (!p_MsgWindow->Create(m_hWnd, _T("通知")))
            {
                AfxMessageBox(L"Create Failed!"); return -1;
            }
            p_MsgWindow->SetMsg(L"高仿QQ新闻右下角弹窗", *cmsg, L"http://blog.csdn.net/jackystudio");
            p_MsgWindow->Show();
            break;
        }
    
        return LRESULT();
    }

    这里我是在收到消息后弹了个窗,有兴趣的访问一下这个 http://blog.csdn.net/jackystudio 博客,我从这里找的漂亮的弹窗程序

    注意这个函数的两个参数[ WPARAM wParam, LPARAM lParam ],这个是可以自己类型转换的,常用的可能就是这种,第一个参数为消息类型,第二个参数为字符串,整数等其他参数,这里是个Cstring字符串

    这两个参数是在PostMessage函数中传进来的,下面会看到

    3、添加消息处理映射

    有了消息ID和处理函数,还要把两者关联起来,这就是消息映射同样是在主类中操作,找到MESSAGE_MAP

    BEGIN_MESSAGE_MAP(CMFCDLLTestDlg, CDialogEx)
        ON_WM_SYSCOMMAND()
        ON_WM_PAINT()
        ON_WM_QUERYDRAGICON()
        ON_BN_CLICKED(IDC_WIN_TEXT, &CMFCDLLTestDlg::OnBnClickedWinText)
        ON_BN_CLICKED(IDC_NEW_DLG, &CMFCDLLTestDlg::OnBnClickedNewDlg)
        ON_BN_CLICKED(IDC_MESSAGE, &CMFCDLLTestDlg::OnBnClickedMessage)
    
        ON_MESSAGE(TEST_SENDMSG, &CMFCDLLTestDlg::OnTestSendmsg)
    END_MESSAGE_MAP()

    可以看到系统消息和按钮点击事件的映射都是在这里的,需要注意的是看清楚是主类的消息映射 BEGIN_MESSAGE_MAP(CMFCDLLTestDlg, CDialogEx) ,我就第一次写在了About类的里面

    2.2 发送消息

    在子线程函数中用PostMessage发送消息,一般用这个,SendMessage也行,一个同步一个异步

    // 省略线程函数其他逻辑
    // ...
    // 发送消息
    ::PostMessage(AfxGetMainWnd()->GetSafeHwnd(), TEST_SENDMSG, (WPARAM)TEST_SENDMSG, (LPARAM)cmsg);

    这里需要注意PostMessage函数加了作用域限定符,否则这个函数有好几个,调用方法不同

    第一个参数是主窗口句柄,第二个参数是消息ID,第三、四个参数对应上面消息处理函数的两个参数

    然后当发送消息函数被执行的时候,窗口主线程就会收到消息,执行创建窗口函数

    当然只要把消息ID和参数一换,比如说换成某个按钮的点击事件ID或者系统消息ID,就可以做些其他事情了  

    3、参考文章

    C++ Part8 MFC中的AfxBeginThread的使用方法(代码实例)

    使用MFC中的AfxBeginThread创建多线程

    建立非模态对话框与在线程中建立非模态对话框

    MFC SendMessage()函数传递字符串

  • 相关阅读:
    识别IE11浏览器
    国庆过后老革命
    有些东西再忙也要做
    云计算
    SVN下Update出现代码文件删除状态问题
    如何避免历史回退到登录页面
    CodeSmith连Oracle
    NHibernate直接执行SQL进行插入
    nhibernate实体类主键ID赋值问题
    NHibernate不支持复杂的linq,就一定要用DataTable这么低级吗
  • 原文地址:https://www.cnblogs.com/jixiaohua/p/12117147.html
Copyright © 2011-2022 走看看