抖音热门数字时钟设计

win32GDI项目数字时钟

前言:基于win32GDI绘图制作抖音热门数字时钟

定时器

开启定时器
//定义定时器ID
#define IDT_TIME 1001
//设置定时器
SetTimer(hWnd
         , IDT_TIME //定时器ID
         , 1000     //定时间隔 单位毫秒ms
         , NULL);   //参数为NULL时,定时向程序投递WM_TIMER消息
匹配定时器消息
    case WM_TIMER:
        switch (wParam)
        {
            case IDT_TIME:
                {
                    HDC hdc = GetDC(hWnd);
                    static int y = 0;
                    TextOut(hdc, 0, y += 20, L"定时器开启第",6);
                    ReleaseDC(hWnd, hdc);
                }
                break;
            default:
                break;
        }
        break;
关闭定时器
KillTimer(hWnd, IDT_TIME);

系统时间

系统时间结构体 SYSTEMTIME

获取系统时间
    wchar_t szTime[100];
    SYSTEMTIME currentTime;
    
    GetLocalTime(&currentTime);
            wsprintf(szTime, L"%.2d %.2d %.2d %.2d:%.2d:%.2d\n", currentTime.wYear,
                currentTime.wMonth, currentTime.wDay, currentTime.wHour, currentTime.wMinute, currentTime.wSecond);
            TextOut(hdc, 0, 0, szTime, wcslen(szTime) - 1);

定时器+时钟 = 简陋的数字时钟

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    wchar_t szTime[100];
    SYSTEMTIME currentTime;
    switch (message)
    {
    case WM_CREATE:
        SetTimer(hWnd, IDT_TIME, 1000, NULL);
        break;
    case WM_RBUTTONDOWN:
        KillTimer(hWnd, IDT_TIME);
        break;
    case WM_TIMER:
        switch (wParam)
        {
        case IDT_TIME:
        {
            HDC hdc = GetDC(hWnd);
            GetLocalTime(&currentTime);
            wsprintf(szTime, L"%.2d %.2d %.2d %.2d:%.2d:%.2d\n", currentTime.wYear,
                currentTime.wMonth, currentTime.wDay, currentTime.wHour, currentTime.wMinute, currentTime.wSecond);
            TextOut(hdc, 0, 0, szTime, wcslen(szTime) - 1);
            ReleaseDC(hWnd, hdc);
        }
            break;
        default:
            break;
        }
        break;
    case WM_COMMAND:
        break;
    case WM_PAINT:
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

效果显示

去标题栏

创建窗口的时候自定义窗口风格

    // 创建主窗口
    HWND hwnd = CreateWindowEx(
        0,          // dwExStyle,扩展样式   
        szClassName,        // lpClassName,类名           
        L"时钟",  // lpWindowName,标题      
        WS_POPUP|WS_SYSMENU|WS_SIZEBOX, // dwStyle,窗口风格 WS_POPUP|WS_SYSMENU去标题栏所需宏
        100,        // X,初始 X 坐标        
        100,        // Y,初始 Y 坐标        
        300,        // nWidth,宽度            
        300,        // nHeight,高度           
        NULL,           // hWndParent,父窗口句柄         
        NULL,           // hMenu,菜单句柄       
        hInstance,      // hlnstance,程序实例句柄     
        NULL);          // lpParam,用户数据     

移动窗口

截取DefWindowProc消息

    case WM_NCHITTEST:
    {
        UINT nHitTest;
        //截取DefWindowProc消息
        nHitTest = DefWindowProc(hwnd, WM_NCHITTEST, wParam, lParam);
        //如果鼠标左键按下 GetAsyncKeyState函数的返回值小于0
        if (nHitTest == HTCLIENT && GetAsyncKeyState(MK_LBUTTON) < 0)
        {
            //改变DefWindowProc消息
            nHitTest = HTCAPTION;
        }
        return nHitTest;
    }
        break;

给系统菜单追加菜单项

定义菜单ID
#define IDM_HELP 1001
#define IDM_TOPMOST 1002
追加菜单
case WM_CREATE:
    {
        HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);    //获取系统菜单
        AppendMenu(hSysMenu, MF_SEPARATOR, 0, NULL);    //添加分割线
        AppendMenu(hSysMenu, MF_STRING, IDM_TOPMOST, L"总是在前");
        AppendMenu(hSysMenu, MF_STRING, IDM_HELP, L"帮助");
    }

右键菜单

这个不能算是右键菜单,因为截取了DefWindowProc消息,多以对客户区的右键相当于对标题栏的右键弹出的是系统菜单

    case WM_CONTEXTMENU:
    {
        POINT pt;
        //lParam包含了鼠标的位置消息 低位x,高位y
        pt.x = LOWORD(lParam);
        pt.y = HIWORD(lParam);
        //获取系统菜单
        HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
        //弹出系统菜单
        int nId = TrackPopupMenu(hSysMenu, TPM_LEFTALIGN | TPM_RETURNCMD, pt.x, pt.y, 0, hwnd, NULL);
        if (nId > 0)
            SendMessage(hwnd, WM_SYSCOMMAND, nId, 0);
        return 0;
    }
        break;

对菜单操作进行响应

全局添加是否顶置标识符
static int s_bTopMost = 0;

响应菜单

注册窗口的时候窗口风格必须带上WS_SYSMENU

    case WM_SYSCOMMAND:
        {
            int nId = wParam;
            switch (nId)
            {
            case IDM_HELP:
                MessageBox(hwnd, L"一个小时钟程序", L"帮助", 0);
                break;
            case IDM_TOPMOST://窗口顶置
            {
                HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
                if (s_bTopMost)
                {
                    //取消选中
                    CheckMenuItem(hSysMenu, IDM_TOPMOST, MF_UNCHECKED);
                    //取消顶置窗口
                    SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE);
                    s_bTopMost = FALSE;
                }
                else
                {
                    //选中
                    CheckMenuItem(hSysMenu, IDM_TOPMOST, MF_CHECKED);
                    //顶置
                    SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE);
                    s_bTopMost = TRUE;
                }
                return DefWindowProc(hwnd, WM_SYSCOMMAND, nId, 0);
            }
                break;

完整代码显示

#include <windows.h>
#define IDM_HELP 1001
#define IDM_TOPMOST 1002

// 窗口函数的函数原形
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);

int APIENTRY WinMain(HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR     lpCmdLine,
    int       nCmdShow)
{
    WCHAR szClassName[] = L"MainWClass";//窗口类的名称
    WNDCLASSEX wndclass;

    // 用描述主窗口的参数填充WNDCLASSEX结构
    wndclass.cbSize = sizeof(wndclass); // 结构的大小
    wndclass.style = CS_HREDRAW | CS_VREDRAW;   // 指定如果大小改变就重画
    wndclass.lpfnWndProc = MainWndProc; // 窗口函数指针
    wndclass.cbClsExtra = 0;        // 没有额外的类内存
    wndclass.cbWndExtra = 0;        // 没有额外的窗口内存
    wndclass.hInstance = hInstance;     // 实例句柄 
    wndclass.hIcon = LoadIcon(NULL,
        IDI_APPLICATION);   // 使用预定义图标
    wndclass.hCursor = LoadCursor(NULL,
        IDC_ARROW);     // 使用预定义的光标
    wndclass.hbrBackground = (HBRUSH)
        ::GetStockObject(WHITE_BRUSH);  // 使用白色背景画刷
    wndclass.lpszMenuName = NULL;       // 不指定菜单
    wndclass.lpszClassName = szClassName;   // 窗口类的名称   
    wndclass.hIconSm = NULL;        // 没有类的小图标

                                    // 注册这个窗口类
    RegisterClassEx(&wndclass);

    // 创建主窗口
    HWND hwnd = CreateWindowEx(
        0,          // dwExStyle,扩展样式   
        szClassName,        // lpClassName,类名           
        L"时钟",  // lpWindowName,标题      
        WS_POPUP|WS_SYSMENU|WS_SIZEBOX, // dwStyle,窗口风格 
        100,        // X,初始 X 坐标        
        100,        // Y,初始 Y 坐标        
        300,        // nWidth,宽度            
        300,        // nHeight,高度           
        NULL,           // hWndParent,父窗口句柄         
        NULL,           // hMenu,菜单句柄       
        hInstance,      // hlnstance,程序实例句柄     
        NULL);          // lpParam,用户数据         

    if (hwnd == NULL)
    {
        MessageBox(NULL, L"创建窗口出错!", L"error", MB_OK);
        return -1;
    }

    // 显示窗口,刷新窗口客户区
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    // 从消息堆中取出消息
    MSG msg;
    while (::GetMessage(&msg, NULL, 0, 0))
    {
        // 转化键盘消息
        TranslateMessage(&msg);
        // 将消息发送到相应的窗口函数
        DispatchMessage(&msg);
    }

    // 当GetMessage返回0时程序结束
    return msg.wParam;
}

static int s_bTopMost = 0;
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    TCHAR szText[] = L"第一个win32程序!";
    switch (message)
    {
    case WM_CREATE:
    {
        HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
        AppendMenu(hSysMenu, MF_SEPARATOR, 0, NULL);    //添加分割线
        AppendMenu(hSysMenu, MF_STRING, IDM_TOPMOST, L"总是在前");
        AppendMenu(hSysMenu, MF_STRING, IDM_HELP, L"帮助");
    }
        break;
    case WM_NCHITTEST:
    {
        UINT nHitTest;
        //截取DefWindowProc消息
        nHitTest = DefWindowProc(hwnd, WM_NCHITTEST, wParam, lParam);
        //如果鼠标左键按下 GetAsyncKeyState函数的返回值小于0
        if (nHitTest == HTCLIENT && GetAsyncKeyState(MK_LBUTTON) < 0)
        {
            //改变DefWindowProc消息
            nHitTest = HTCAPTION;
        }
        return nHitTest;
    }
        break;
    case WM_CONTEXTMENU:
    {
        POINT pt;
        //lParam包含了鼠标的位置消息 低位x,高位y
        pt.x = LOWORD(lParam);
        pt.y = HIWORD(lParam);
        //获取系统菜单
        HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
        //弹出系统菜单
        int nId = TrackPopupMenu(hSysMenu, TPM_LEFTALIGN | TPM_RETURNCMD, pt.x, pt.y, 0, hwnd, NULL);
        if (nId > 0)
            SendMessage(hwnd, WM_SYSCOMMAND, nId, 0);
        return 0;
    }
        break;
    case WM_SYSCOMMAND:
        {
            int nId = wParam;
            switch (nId)
            {
            case IDM_HELP:
                MessageBox(hwnd, L"一个小时钟程序", L"帮助", 0);
                break;
            case IDM_TOPMOST://窗口顶置
            {
                HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
                if (s_bTopMost)
                {
                    //取消选中
                    CheckMenuItem(hSysMenu, IDM_TOPMOST, MF_UNCHECKED);
                    //取消顶置窗口
                    SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE);
                    s_bTopMost = FALSE;
                }
                else
                {
                    //选中
                    CheckMenuItem(hSysMenu, IDM_TOPMOST, MF_CHECKED);
                    //顶置
                    SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE);
                    s_bTopMost = TRUE;
                }
                return DefWindowProc(hwnd, WM_SYSCOMMAND, nId, 0);
            }
                break;
            default:
                break;
            }
        }
        break;
    case WM_PAINT: // 窗口客户区需要重画
    {
        HDC hdc;
        PAINTSTRUCT ps;
        // 使无效的客户区变的有效,并取得设备环境句柄
        hdc = BeginPaint(hwnd, &ps);
        // 显示文字
        //TextOut(hdc, 10, 10, szText, wcslen(szText));
        EndPaint(hwnd, &ps);
        return 0;
    }
    case WM_DESTROY: // 正在销毁窗口
        // 向消息队列投递一个WM_QUIT消息,促使GetMessage函数返回0,结束消息循环
        PostQuitMessage(0);
        return 0;
    }
    // 将我们不处理的消息交给系统做默认处理
    return DefWindowProc(hwnd, message, wParam, lParam);
}

设置坐标

case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);

            //获取客户区大小
            RECT rt;
            GetClientRect(hWnd, &rt);
            int cx = rt.right;
            int cy = rt.bottom;

            SetViewportExtEx(hdc, cx, cy, NULL);    //设置x,y坐标轴
            SetViewportOrgEx(hdc, 0, 0, NULL);      //设置原点
            EndPaint(hWnd, &ps);
        }

了解这些win32基础知识之后我们来绘制一个数字时钟

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352