当前位置:C++技术网 > 精选软件 > win32不使用计时器实现动态文字提示的效果

win32不使用计时器实现动态文字提示的效果

更新时间:2015-12-26 18:35:00浏览次数:1+次

    在文章《win32使用计时器实现动态的等待提示字符效果大全(组图) 》中,我们用计时器的方式实现了动态提示的效果。

    然而,你想过没有,其实我们可以不用计时器就可以实现动态提示的效果哦。我们可以仔细来分析这个计时器的作用的本质以及动态提示的本质。这是我们实现的效果图:

不使用计时器实现动态文字提示的效果

【不使用计时器实现动态文字提示的效果】
    计时器的本质就是定时的触发,这样可以提供一个源源不断的动力,驱动着一个事情的持续进行,比如驱使这个动态提示效果的持续完成。
    那么我们只要能够提供一种持续驱动的机制,就可以不需要计时器了。有没有呢?开动大脑吧,当然有啦。思维千万别局限住了。
    我们先来看看动态提示的本质咯。动态提示就是利用持续的WM_PAINT消息来不停的输出,当然需要将上一次的输出擦除。而源源不断的产生WM_PAINT则是因为计时器不断的在人为的生产WM_PAINT消息。
    那么这两者似乎密不可分,然而,分起来也可以毫无关联。只要你思维换着位置想,一切就大不一样。计时器在这里只是提供一个产生WM_PAINT的作用,而且是定时的产生的。定时的时间稍长一点,不要让消息产生的太快让提示频率太高而让画面闪烁。
    基于上面的分析,我们也可以实现。方法也很简单,那就是在处理完WM_PAINT消息时人为的产生WM_PAINT消息,调用的函数和WM_TIMER消息中的一样。这样,消息的一处理完就马上产生了另一个消息,这样就形成了一个持续的驱动力,可以让这个效果一直持续下去。这样就替代了计时器了。
    然而事实上,这样你看到的效果是界面不停的闪烁。如何破?你可以使用线程休眠的函数Sleep,让线程暂停执行一下子,这样就可以控制窗口显示的提示文字的输出频率,就很好的解决了闪烁的问题。Sleep函数只需要传入时间值即可,以毫秒为单位,1秒等于1000毫秒。
    当然,这个不是唯一的方案。提供持续的驱动的方案,我们还有一个巧妙的方法。然而这个方法一般对win32了解不够深入的人是不知道的。我们就是利用无效区域与WM_PAINT消息的关系来达到这个目的。如果WM_PAINT消息中我们不让无效区域变得有效,也就意味着无效区域一直存在,而只要无效区域存在,系统就要自动的产生一个WM_PAINT消息。那么这个就可以被我们巧妙地利用。而BeginPaint函数会自动让无效区域变得有效。我们既然要绘图,又不能使用BeginPaint,那么我们就可以使用GetDC来获取客户区DC,同样可以作画哦。对于无效区域和WM_PAINT的关系的分析,请阅读《WM_PAINT消息处理中的客户区重绘消息死循环问题详细分析和代码验证》。
     前面一种方法就是在处理完后加入下面一个语句:
InvalidateRect(hwnd,NULL,TRUE);//产生WM_PAINT消息
    来产生消息,维持持续的驱动。而后一种方法就不需要这个来维持了。我们一直都没有让无效区域变得有效,所以从窗口第一次显示系统自动产生一个WM_PAINT开始,就会一直持续下去。当然我们改变窗口的大小也会产生这个消息。
    虽然利用了无效区域这个特点,然而它只是提供一个持续驱动的特性而已。如果不想画面闪烁,还是要用Sleep函数哦。同时,我们会发现,我们还是需要一个让客户区重画擦除背景的需求,否则我们的点的提示就会出现点都输出来之后就不会再看到动态的效果了。所以,还是要加上InvalidateRect函数来擦除背景。不过此函数在这个使用环境下,主要是提供的擦除的功能哦。
    不过综上所述呢,第一种方法似乎更加方便,直接自己产生消息的同时还会让客户区背景擦除,一举两得。不过第二种方式也是一个巧妙的使用,说不定在某些场合用得上哦。
    下面是完整的代码:
#include "windows.h"
#include <tchar.h>
// - 项目是Unicode字符集
LRESULT CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
    TCHAR Info[100]=_T("【C++技术网http://www.cjjjs.com】");
    PAINTSTRUCT ps;
    switch (message)
    {
    case WM_PAINT:
        {
            #define COUNT 9
            static int iCount=0;
            static TCHAR Dot[COUNT][10]={_T("."),_T(".."),_T("..."),_T("...."),_T("....."),_T("......"),_T("......."),_T("........"),_T("........")};
            //static TCHAR Dot[COUNT][10]={_T("-"),_T("/"),_T("|"),_T("\\")};
            //static TCHAR Dot[COUNT][10]={_T("╱"),_T("┊"),_T("╲"),_T("┈")};
            //static TCHAR Dot[COUNT][10]={_T("①"),_T("②"),_T("③"),_T("④"),_T("⑤"),_T("⑥")};
            //static TCHAR Dot[COUNT][10]={_T("┹"),_T("┩"),_T("┱"),_T("┢")};
            //static TCHAR Dot[COUNT][10]={_T("卍"),_T("卐")};

            //空闲扫面
            HDC hdc = GetDC(hwnd);//利用无效区域和WM_PAINT的关系特点
            SelectObject(hdc,GetStockObject(SYSTEM_FIXED_FONT));
            TCHAR Tip[100]=_T("");
            wsprintf(Tip,_T("正在扫描病毒%s"),Dot[iCount++%COUNT]);
            TextOut(hdc,10,20,Tip,lstrlen(Tip));

            InvalidateRect(hwnd,NULL,TRUE);//不停地产生WM_PAINT消息(第一种方法)和(让客户区擦除背景,第一第二钟方法都要用)
            Sleep(250);//延时显示动态的效果,两种方法都要用
            ReleaseDC(hwnd,hdc);
        }
        return 0;

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    default:
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrev,LPSTR lpCmd,int iShow)
{
    TCHAR ClassName[] = _T("MyClass");
    TCHAR title1[] = _T("C++技术网http://www.cjjjs.com");
    WNDCLASS wndClass;
    wndClass.cbClsExtra=0;
    wndClass.cbWndExtra=0;
    wndClass.hbrBackground= (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
    wndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
    wndClass.hInstance = hInstance;
    wndClass.lpfnWndProc = WinProc;
    wndClass.lpszClassName = ClassName;
    wndClass.lpszMenuName=NULL;
    wndClass.style=CS_HREDRAW|CS_VREDRAW;

    if(!RegisterClass(&wndClass)) return 0;
    HWND hwnd = CreateWindow(ClassName,title1,WS_OVERLAPPEDWINDOW,0,0,600,500,NULL,NULL,hInstance,NULL);
    ShowWindow(hwnd,SW_SHOWNORMAL);

    MSG msg;
    while (TRUE)
    {
        if(GetMessage(&msg,NULL,0,0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return msg.wParam;
}