• MFC界面更新实现方法


    1.更新窗口

    即采用UpdateWindow()函数立即发送WM_PAINT消息更新整个窗口。

    void CEditTestDlg::OnBnClickedBtnSysUpdate()
    {
        CString csTmp;
        int i = 0;
        while (i < 100)
        {
            Sleep(20);
            i += 1;
            csTmp.Format(_T("%d"),i);
            m_value = csTmp;//无法更新只显示结果
            //m_editNum.SetWindowText(csTmp);//无法更新也不显示结果
            UpdateData(FALSE);
            UpdateWindow();//能更新但再次操作会卡死
            //Invalidate(FALSE);//无法更新只显示结果
            //RedrawWindow(NULL,NULL,RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE);//RDW_INVALIDATE和Invalidate()效果一样,RDW_ERASE导致闪烁
        }
    }

    但是这会导致界面假死,更新过程中无法对窗口进行任何操作。控件的Control变量有时候无法更新Invalidate()一般都在多文档对话框里使用,RedrawWindow()是前两个都会去调用的函数,方式更多。详情见:MFC重绘函数

    2. 定时器实现

    在需要更新的位置调用SetTimer()启动定时器,在定时器响应函数OnTimer()里面来处理更新,可以同时启用多个定时器更新多个位置。

    启动定时器:

    void CEditTestDlg::OnBnClickedBtnTimerUpdate()
    {
        this->SetTimer(1,1,NULL);
        this->SetTimer(2,1,NULL);
    }

    定时器内部处理:

    void CEditTestDlg::OnTimer(UINT_PTR nIDEvent)
    {
        switch (nIDEvent)
        {
        case 1:
            if (tmp >= 100)
            {
                this->KillTimer(1);
                MessageBox(_T("定时器1停止!"), NULL, NULL);
                return;
            }
            Sleep(20);
            tmp += 1;
            m_value.Format(_T("%d"),tmp);
            UpdateData(FALSE);
            break;
        case 2:
            if (tmp1 >= 200)
            {
                this->KillTimer(2);
                MessageBox(_T("定时器2停止!"), NULL, NULL);
                return;
            }
            Sleep(20);
            tmp1 += 1;
            m_value2.Format(_T("%d"),tmp1);
            UpdateData(FALSE);
        default:
            break;
        }
        CDialog::OnTimer(nIDEvent);
    }

    通过定时器界面不会假死,实现也简单明了。

    3. 线程更新

    创建一个新的线程来更新界面,创建线程:

    void CEditTestDlg::OnBnClickedBtnThreadUpdate()
    {
        CWinThread* pThread;
        pThread = AfxBeginThread(UpdateThread,this);
    }

    线程内部实现:

    static UINT UpdateThread(LPVOID lpParam)
    {
        CEditTestDlg *dlg = (CEditTestDlg*) lpParam;
        int i = 0;
        while (i < 200)
        {
            Sleep(20);
            i += 1;
            dlg->m_value2.Format(_T("%d"), i);
            //dlg->UpdateData(FALSE);//release下可行
            dlg->m_editCtl.SetWindowText(dlg->m_value2);//使用control变量
            //dlg->GetDlgItem(IDC_EDIT2)->SetWindowText(dlg->m_value2);
        }
        return 0;
    }

    在这里,最好不要用UpdateData(FALSE)来显示到界面,在Debug下回奔溃,而Release模式下没有任何问题,具体见:线程调用UpdateData函数出错

    4. 线程中发送自定义消息更新

    在线程中给窗口发送自定义的更新界面的消息,让消息加入系统消息队列达到更新界面的目的。自定义消息可参照:MFC添加自定义消息

    void CEditTestDlg::OnBnClickedBtnMsgUpdate()
    {
        CWinThread* pThread;
        pThread = AfxBeginThread(SendMsgThread,this);
    }
    static UINT SendMsgThread(LPVOID lpParam)
    {
        CEditTestDlg *dlg = (CEditTestDlg*) lpParam;
        int i = 0;
        while (i < 100)
        {
            Sleep(20);
            i += 1;
            dlg->m_value2.Format(_T("%d"), i);
            //PostMessage(dlg->m_hWnd,WM_UPDATEDATA,FALSE,NULL);
            //SendMessage(dlg->m_hWnd,WM_UPDATEDATA,FALSE,NULL);
            SendMessageTimeout(dlg->m_hWnd, WM_UPDATEDATA, FALSE,NULL, SMTO_BLOCK, 1000, NULL);
        }
        return 0;
    }

    发送消息的时候PostMessage(),SendMessage()SendMessageTimeout()都可以实现,具体区别见:SendMessage和PostMessage区别

    5. 设备绘制更新

    直接在界面中不停的绘制变化的部分,这种方法也会造成假死。

    void CEditTestDlg::OnBnClickedBtnDrawUpdate()
    {
        CString csTmp;
        int i = 0;
        CDC* pDC = this->GetDC();
        while (i < 100)
        {
            Sleep(20);
            i += 1;
            csTmp.Format(_T("%d"),i);
            pDC->TextOut(20, 100, csTmp);
        }
        ReleaseDC(pDC);
    }

    6. STATIC控件更新

    给STATIC控件赋值更新,同样会造成假死现象。(值得一提的是以前在VC6.0中可以对EIDT控件使用同样的方法更新而现在去测试却不行,希望有经验的人给予指导。

    void CEditTestDlg::OnBnClickedBtnStaticUpdate()
    {
        CString csTmp;
        int i = 0;
        while (i < 100)
        {
            Sleep(20);
            i += 1;
            csTmp.Format(_T("%d"),i);
            m_csStaticNum = csTmp;//能更新但再次操作会卡死
            //m_staticCtlNum.SetWindowText(csTmp);//不更新也不显示结果
            UpdateData(FALSE);
        }
    }

    7. 发送系统消息更新

    直接给系统消息循环发送WM_PAINT消息来更新界面,但是同样会出现假死情况,所以可以创建一个函数DoEvent()实现:在有系统消息,如拖动点击等消息时,暂停处理我们发送的消息而优先去处理系统消息。

    void CEditTestDlg::OnBnClickedBtnMsg()
    {
        CString csTmp;
        int i = 0;
        while (i < 100)
        {
            Sleep(20);
            i += 1;
            csTmp.Format(_T("%d"),i);
            m_value = csTmp;//能更新但再次操作会卡死
            //m_editNum.SetWindowText(csTmp);//无法更新也不显示结果
            UpdateData(FALSE);
            GetDlgItem(IDC_EDIT1)->SendMessage(WM_PAINT);//能更新但再次操作会卡死
            DoEvents();//转出处理系统消息
        }
    }
    //有系统消息时暂停处理系统消息
    void DoEvents()
    {
        MSG msg; //定义一个MSG类型的变量
        while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) //获取消息并把该消息从消息队列中移除(防止重复响应)。
        {
            TranslateMessage(&msg);//翻译消息 在合适的机会产生char消息
            DispatchMessage(&msg); //将消息移交给过程函数
        }
    }

    但是出现的问题是,我们在拖动对话框的时候,界面停止了更新。

    所以比较而言,线程发送消息和定时器效果相对较好,界面不会假死,在进行拖动等操作的时候也不会出现停止等待的现象。

     

  • 相关阅读:
    [翻译]Linux 内核里的数据结构 —— 基数树
    spring各版本下载地址
    两台机子的repcached Memcache 的安装与实验
    非root用户Memcached repcached安装
    VMVare 桥接上网
    JDBC executeBatch 抛出异常停止
    Ehcache jgroups方式同步缓存出现问题总结
    jquery $提示缺少对象$提示缺少对象
    Struts2标签遍历List<Map<String,String>>
    linux与windows回车换行符的区别
  • 原文地址:https://www.cnblogs.com/skywatcher/p/3572311.html
Copyright © 2020-2023  润新知