VC++窗口創建過程,圖形繪制,時鍾程序


創建窗口步驟:

(1)注冊窗口類(RegisterClassEx)

(2)創建窗口(CreateWindowEx

(3)在桌面顯示窗口(ShowWindow)

(4)更新窗口客戶區(UpdateWindow)

(5)進入無限的消息獲取和處理的循環:獲取消息(GetMessage);分派消息至窗口函數處理(DisPatchMessage);

   如果是WM_QUIT,函數(GetMessage)返回False,消息循環結束,程序退出。

注冊窗口類需要初始化一個窗口類結構,將其寫成一個函數如下:

ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;  //窗口類結構
    wcex.cbSize = sizeof(WNDCLASSEX); //結構大小
    wcex.style          = CS_HREDRAW | CS_VREDRAW|CS_OWNDC;//CS:class style此窗口類派生的窗口具有的風格
    //CS_OWNDC使得windows將每次對DC的設置保存下來,CS_HREDRAW | CS_VREDRAW窗口大小變化就刷新
    wcex.lpfnWndProc    = WndProc;    //窗口函數指針                     
    wcex.cbClsExtra     = 0;  //緊跟在窗口類結構后的附加字節數
    wcex.cbWndExtra     = 0;  //緊跟在窗口事例后的附加字節數
    wcex.hInstance      = hInstance;//本模塊的實例句柄
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CLOCKWINDOW));//窗口左上角圖標句柄
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);//光標句柄
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW); //背景畫刷句柄
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_CLOCKWINDOW);//菜單名
    //wcex.lpszMenuName   =NULL;  //無菜單
    wcex.lpszClassName  = szWindowClass;  //此窗口類名
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));//小圖標句柄
    return RegisterClassExW(&wcex);  //注冊此窗口類
}

 

創建窗口、顯示窗口、刷新客戶區寫成一個函數如下:

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    hInst = hInstance; // 將實例句柄存儲在全局變量中
   HWND hWnd = CreateWindowW(szWindowClass,       //窗口類名
                             szTitle,             //窗口標題
                             WS_OVERLAPPEDWINDOW, //窗口風格 WS:window style                    
                             CW_USEDEFAULT,       //初始位置X坐標
                             CW_USEDEFAULT,       //初始位置Y坐標
                             500,                 //寬度
                             500,                 //高度
                             nullptr,             //父窗口句柄
                             nullptr,             //菜單句柄
                             hInstance,           //程序實例句柄
                             nullptr);            //用戶數據
   if (!hWnd)
   {
      return FALSE;
   }
   ShowWindow(hWnd, nCmdShow);  //顯示窗口
   UpdateWindow(hWnd);          //刷新客戶區
   return TRUE;
}

因此主函數可以寫為:

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);
    // 初始化全局字符串
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_CLOCKWINDOW, szWindowClass, MAX_LOADSTRING);

    MyRegisterClass(hInstance);
    // 執行應用程序初始化: 
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CLOCKWINDOW));

    MSG msg;
    // 主消息循環: 
    while (GetMessage(&msg, nullptr, 0, 0))//GetMessage返回False程序結束
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return (int) msg.wParam;  //程序結束時返回最后一個MSG的wParam。
}

在窗口作圖

測試一:先打開notepad,之后運行此代碼

    HWND hWnd;
    HDC hDC;
    hWnd = ::FindWindow(_TEXT("Notepad"), NULL);
    hDC = ::GetDC(hWnd);
    while (::IsWindow(hWnd))
    {    
        ::SetTextColor(hDC, RGB(255, 0, 0));
        ::SetBkColor(hDC, RGB(0, 0, 0));
        ::TextOut(hDC, 10, 10, _T("this is a test."), sizeof("this is a test.") - 2);

        HPEN hPen = CreatePen(NULL,4,RGB(255,255,255));
        ::SelectObject(hDC, hPen);
        ::SelectObject(hDC, ::GetStockObject(BLACK_BRUSH));
        Ellipse(hDC, 0, 0, 500, 500);
        Sleep(1000);
        ::SelectObject(hDC, ::GetStockObject(WHITE_BRUSH));
        Ellipse(hDC, 0, 0, 500, 500);
        Sleep(1000);
        ::SelectObject(hDC, ::GetStockObject(LTGRAY_BRUSH));
        Ellipse(hDC, 0, 0, 500, 500);
        Sleep(1000);
        ::SelectObject(hDC, ::GetStockObject(GRAY_BRUSH));
        Ellipse(hDC, 0, 0, 500, 500);
        Sleep(1000);
        ::SelectObject(hDC, ::GetStockObject(DKGRAY_BRUSH));
        Ellipse(hDC, 0, 0, 500, 500);
        Sleep(1000);
        ::SelectObject(hDC, ::GetStockObject(DKGRAY_BRUSH));
        Ellipse(hDC, 0, 0, 500, 500);
        Sleep(1000);
    }
    ReleaseDC(hWnd, hDC);

繪圖首先要取得設備環境句柄

            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);  //取得(窗口客戶區無效區域)設備環境句柄
            //繪圖代碼
            //EndPaint(hWnd, &ps);
            HDC hdcW = ::GetWindowDC(hWnd);   //取得整個窗口設備環境句柄
            HDC hdcD = ::GetDC(hWnd);         //取得窗口客戶區設備環境句柄(函數可用在任何地方)        

接着有時為了作圖方便需要修改默認坐標系

void SetIsotropic(HWND hWnd,HDC hdc)
{
    RECT rect;
    GetClientRect(hWnd, &rect);       //取得客戶區大小
    ::SetMapMode(hdc, MM_ANISOTROPIC);  //自定義坐標系MM_ANISOTROPIC:X!=Y,MM_ISOTROPIC:X=Y
    ::SetWindowExtEx(hdc, 500, 500, NULL);   //邏輯刻度,第四個參數可用於返回原來的大小
    ::SetViewportExtEx(hdc, rect.right, -rect.bottom, NULL); //像素刻度(坐標方向),第四個參數可用於返回原來的大小
    ::SetViewportOrgEx(hdc, rect.right / 2, rect.bottom / 2, NULL);  
    //修改坐標系(參照之前坐標系的位置坐標),第四個參數可用於返回原來的原點
}

修改完坐標系后開始繪制時鍾表面

void paintClock(HWND hWnd,HDC hdc)
{
    HPEN hPenTri, hPenTime, hPenCent;
    HBRUSH hBrushTr, hBrushTime, hBrushCent;
    int colorUseR = (rand() % (255 - 0 + 1)) + 0;   //(rand() % (b-a+1))+ a; a~b隨機數
    int colorUseG = (rand() % (255 - 0 + 1)) + 0;
    int colorUseB = (rand() % (255 - 0 + 1)) + 0;
    hPenTri = CreatePen(NULL, 4, RGB(255, colorUseG, 240));
    hBrushTr = ::CreateSolidBrush(RGB(255, colorUseG, 240));
    bankColor = RGB(255, colorUseG, 240);
    hPenTime = CreatePen(NULL, 4, RGB(colorUseR, 240, 240));
    hBrushTime = ::CreateSolidBrush(RGB(colorUseR, 240, 240));
    hPenCent = ::CreatePen(NULL, 4, RGB(240, 240, colorUseB));
    hBrushCent = ::CreateSolidBrush(RGB(240, 240, colorUseB));

    SetIsotropic(hWnd,hdc);
///三角形////////////////////////////////////////////////////////////////////////////////////
    //SetDCBrushColor(hdc, RGB(255, 255, 255));//(無效)
    ::SelectObject(hdc, hPenTri);
    ::SelectObject(hdc, hBrushTr);
  //POINT Mypoint[12] = { (250,10),(375,33.5),(466.5,125),(490,250),(466.5,375),(375,466.5),(250,490),(125,466.5),(33.5,375),(10,250),(33.5,125),(125,33.5) };//寫法錯誤
    POINT Mypoint[12] = { 0,240,120,207.84,207.84,120,240,0,207.84,-120,120,-207.84,0,-240,-120,-207.84,-207.84,-120,-240,0,-207.84,120,-120,207.84 };
 //::ClientToScreen(hWnd, point);   //投射到屏幕坐標,返回至point
    POINT Mypoint1[3] = { Mypoint[0],Mypoint[4],Mypoint[8] };
    POINT Mypoint2[3] = { Mypoint[1],Mypoint[5],Mypoint[9] };
    POINT Mypoint3[3] = { Mypoint[2],Mypoint[6],Mypoint[10] };
    POINT Mypoint4[3] = { Mypoint[3],Mypoint[7],Mypoint[11] };
    //POINT Mypoint5[4]={ Mypoint1 ,Mypoint2,Mypoint3,Mypoint4}//不好用for循環簡化操作,二維數組用不了??
    Polygon(hdc, Mypoint1, 3);
    Polygon(hdc, Mypoint2, 3);
    Polygon(hdc, Mypoint3, 3);
    Polygon(hdc, Mypoint4, 3);
//圓形===============================================================

    ::SelectObject(hdc, hPenTime);
    ::SelectObject(hdc, hBrushTime);//圖形填充色
    for (int i = 0; i < 12; i++)
    {
        Ellipse(hdc, Mypoint[i].x - 10, Mypoint[i].y - 10, Mypoint[i].x + 10, Mypoint[i].y + 10);
    }
//中心點加文本=======================================================
    ::SelectObject(hdc, hPenCent);
    ::SelectObject(hdc, hBrushCent);
    ::Ellipse(hdc, -5, 5, 5, -5);
    ::SetTextColor(hdc, RGB(0, 0, 0));  //文字顏色
  //::SetBkColor(hdc, TRANSPARENT);  //文字背景色,設置為透明無效
    ::SetBkMode(hdc, TRANSPARENT);  //文字背景透明

    CString strText = _T("時鍾");
    TextOut(hdc, -240, 240, (LPCWSTR)strText, sizeof(strText) - 2);
}

繪制時鍾的指針函數

void DrawHand(HDC hdc, int nLength, int nWidth, int nDegrees, COLORREF clrColor)
{
    double nRadians = (double)nDegrees * 2 * 3.1415926 / 360;
    POINT pt[2];
    pt[0].x = (int)(nLength*sin(nRadians));
    pt[0].y = (int)(nLength*cos(nRadians));
    pt[1].x = pt[0].x /-5;
    pt[1].y = pt[0].y /-5;
    HPEN hPen = ::CreatePen(PS_SOLID, nWidth, clrColor);
    HPEN oldPen = (HPEN)::SelectObject(hdc, hPen);
    ::MoveToEx(hdc, pt[0].x, pt[0].y, NULL);
    LineTo(hdc, pt[1].x, pt[1].y);

    ::SelectObject(hdc, oldPen);
    ::DeleteObject(hPen);
}

在窗口函數WM_CREATE下設置定時器

    case WM_CREATE: 
//當一個應用程序通過CreateWindowEx函數或者CreateWindow函數請求創建窗口時發送此消息,(此消息在函數返回之前發送)。
        SYSTEMTIME time;
        ::GetLocalTime(&time);
        s_PreHour = time.wHour%12;//取余
        s_PreMinute = time.wMinute;
        s_PreSecond = time.wSecond;
        SetTimer(hWnd,   //窗口句柄
                IDT_CLOCK,//TimerID
                1000,     //間隔
                NULL);     //計時器函數指針
        return 0;
        //它應當返回0以使得窗口的創建過程得以繼續。如果對於這個消息程序返回-1,窗口將會被銷毀。
        //並且CreateWindowEx或者CreateWindow函數將會返回一個值為NULL的句柄。

在WM_TIMER下控制指針的變化與重畫

    case WM_TIMER:
        paintClock(hWnd, hDC);
        //paintClock(hWnd, hDC);重畫了時鍾面板,使得覆蓋了舊的時鍾指針
        if (::IsIconic(hWnd))   //如果窗口是最小化
        {
            return 0;
        }
        ::GetLocalTime(&time);
        //HDC hDC = ::GetDC(hWnd);//(無法寫在這里)
        SetIsotropic(hWnd, hDC);//建立坐標系
        if (time.wMinute != s_PreMinute)
        {            
            //DrawHand(hDC, 140, 8, s_PreHour * 30 + s_PreMinute / 2, bankColor);//使用時鍾面板顏色覆蓋原指針
            //DrawHand(hDC, 170, 6, s_PreMinute * 6, bankColor);  
            //覆蓋失敗(不能使得指針顏色完全消失,如同在相同的兩點好幾條畫好幾條線,看起來線條變粗並不像一條直線)
            
            s_PreHour = time.wHour;
            s_PreMinute = time.wMinute;
        }
        if (time.wSecond != s_PreSecond)
        {
            //DrawHand(hDC, 170, 1, s_PreSecond * 6, bankColor);//使用時鍾面板顏色覆蓋原指針
            DrawHand(hDC, 80, 6, s_PreHour * 30 + s_PreMinute / 2, RGB(0,0,0));
            DrawHand(hDC, 120, 4, s_PreMinute * 6, RGB(0, 0, 0));
            DrawHand(hDC, 170, 2, s_PreSecond * 6, RGB(0, 0, 0));
            s_PreSecond = time.wSecond;
        }
        //::MessageBeep(MB_ICONASTERISK);//發出“嘟嘟”聲
        break;

效果圖

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM