用GDI+旋轉多邊形來繪製一個時鐘摸擬小程式

初吻给了烟灬發表於2024-08-22

效果圖

在標頭檔案類中宣告變數

TCHAR m_dayStr[4];    // 日期
    TCHAR m_weekStr[4];  // 星期
    Gdiplus::Font* m_pFont;  // 字型
    Gdiplus::StringFormat m_strFormat;  // 格式化字串
    Gdiplus::Pen* m_pPen;      // 畫筆
    Gdiplus::SolidBrush* m_pBrush;  // 畫刷
    Gdiplus::RectF m_dayRect;      // 日期矩形
    Gdiplus::RectF m_weekRect;      // 星期矩形
    Gdiplus::PointF m_orgPointF; // 圓點座標
    float m_rColok;    //圓半徑

  Gdiplus::PointF hourPts[4];  //時針多邊形陣列
  Gdiplus::PointF mimPts[4];    //分針多邊形陣列
  Gdiplus::PointF scrPts[2];    //秒針陣列

 

在初始化函式中初始變數的值

// 獲得系統時間
SYSTEMTIME sysTime;
GetLocalTime(&sysTime);

// 格式化日期和星期字串
_stprintf_s(m_dayStr,TEXT("%02d"),sysTime.wDay);

TCHAR weekStrs[7][4]={L"",L"",L"",L"",L"",L"",L""};
_stprintf_s(m_weekStr,TEXT("%s"),weekStrs[sysTime.wDayOfWeek]);

// 啟動時間計時器
SetTimer(m_hWnd,11,1000,NULL);

在WM_SIZE中計算圓點,半徑,多邊形分針,時針,秒針的頂點座標陣列值

float cx=LOWORD(lParam);
    float cy=HIWORD(lParam);

        // 計算圓點
    m_orgPointF.X=cx/2;
    m_orgPointF.Y=cy/2;
        
        // 計算半徑
    m_rColok=min(cx,cy)/2;
    m_rColok-=10;

    float r=m_rColok;
    
        // 秒針陣列賦值
    scrPts[0].X=0;
    scrPts[0].Y=-r*9/10;
    scrPts[1].X=0;
    scrPts[1].Y=r*2/10;

    // 分針多邊形座標陣列
    mimPts[0].X=(float)(-r*0.7 / 10);
    mimPts[0].Y=0;
    mimPts[1].X=0;
    mimPts[1].Y=-r * 8/ 10;
    mimPts[2].X=(float)(r*0.7 / 10);
    mimPts[2].Y=0;
    mimPts[3].X=0;
    mimPts[3].Y=r * 2/ 10;

    // 時針多邊形陣列
    hourPts[0].X=-r / 10;
    hourPts[0].Y=0;
    hourPts[1].X=0;
    hourPts[1].Y=-r * 6/ 10;
    hourPts[2].X=r / 10;
    hourPts[2].Y=0;
    hourPts[3].X=0;
    hourPts[3].Y=r * 2/ 10;

        // 日期矩形
    m_dayRect.X=r-16;
    m_dayRect.Y=-10;
    m_dayRect.Width=20;
    m_dayRect.Height=20;

        // 日期矩形
    m_weekRect.X=r-36;
    m_weekRect.Y=-10;
    m_weekRect.Width=20;
    m_weekRect.Height=20;    

用旋轉圖片來繪製多邊形,

圖片旋轉是以圓點為中心來旋轉的,

所以要重新設定座標系圓點為錶盤中心點

自定義函式RotatePolygon來計算多邊形的旋轉,和繪製

// 旋轉多邊形,並繪製
// (繪製物件,多邊形頂點座標陣列,頂點個數,旋轉角度)
void
RotatePolygon(Gdiplus::Graphics* graphics, Gdiplus::PointF* points, int numPoints, float angle) { // 建立旋轉矩陣 Gdiplus::Matrix matrix; matrix.Rotate(angle); // 旋轉多邊形的每個點 Gdiplus::PointF* rotatedPoints = new Gdiplus::PointF[numPoints]; for (int i = 0; i < numPoints; i++) { Gdiplus::PointF point = points[i]; matrix.TransformPoints(&point, 1); rotatedPoints[i] = point; } Gdiplus::Pen pen(Color(255,0,0,0),(numPoints==2) ? 2.0f:1.0f); // 繪製旋轉後的多邊形 graphics->DrawPolygon(&pen, rotatedPoints, numPoints);
  
  
  // 用線性漸變畫刷填充多邊形 graphics
->FillPolygon(&Gdiplus::LinearGradientBrush(rotatedPoints[0],rotatedPoints[2], Color(255,0,0,255),Color(255,255,255,0)),rotatedPoints,numPoints); delete[] rotatedPoints; }

最後在WM_PAINT訊息中繪製

void MyMainWnd::OnPaint(){

    PAINTSTRUCT ps;
    HDC hdc=BeginPaint(m_hWnd,&ps);

    // 建立記憶體dc,建立記憶體點陣圖,並將記憶體點陣圖選入記憶體dc中
    HDC hmdc=CreateCompatibleDC(hdc);;
    HBITMAP hBitmap=CreateCompatibleBitmap(hdc,ps.rcPaint.right,ps.rcPaint.bottom);
    HGDIOBJ hOldMap=SelectObject(hmdc,hBitmap);

    // 建立在記憶體dc中繪圖物件
    Gdiplus::Graphics g(hmdc);
    g.SetSmoothingMode(SmoothingModeAntiAlias); //設定抗鋸齒模式
    

    // 用指定顏色填充整個記憶體點陣圖
    m_pBrush->SetColor(Color(255,128,128,129));
    g.FillRectangle(m_pBrush,0,0,ps.rcPaint.right,ps.rcPaint.bottom);

    // 設定新的座標系原點為錶盤中心點
    Gdiplus::Matrix transform;
    transform.Translate(m_orgPointF.X, m_orgPointF.Y);
    g.SetTransform(&transform);


    float xBegin,yBegin;
    float rClock=m_rColok; // 圓的半徑

    // 用指定顏色的畫刷,繪製錶盤上的刻度
    m_pBrush->SetColor(Color(255,217,222,18));
    for(int i=0;i<60;i++)
    {
        xBegin = (float)( rClock * sin(2 * PI*i / 60));
        yBegin = (float)(rClock * cos(2 * PI*i / 60));

        if (i % 5)
        {
            // 填充小圓點表示小刻度
            g.FillEllipse(m_pBrush,xBegin-2,yBegin-2,4.0f,4.0f);
        }
        else
        {
            // 填充大圓點表示大刻度
            g.FillEllipse(m_pBrush,xBegin-4,yBegin-4,8.0f,8.0f);
        }
    }

    //獲取系統時間
    SYSTEMTIME x;
    GetLocalTime(&x);

    // 繪製顯示日期和星期的矩形區域
    m_pPen->SetColor(Color::Black);
    m_pBrush->SetColor(Color::YellowGreen);
    g.DrawRectangle(m_pPen,m_dayRect);
    g.DrawRectangle(m_pPen,m_weekRect);
    g.FillRectangle(m_pBrush,m_dayRect);
    g.FillRectangle(m_pBrush,m_weekRect);

    // 繪製日期和星期的字串文字
    m_pBrush->SetColor(Color::Black);
    g.DrawString(m_dayStr,-1,m_pFont,m_dayRect,&m_strFormat,m_pBrush);
    g.DrawString(m_weekStr,-1,m_pFont,PointF(m_weekRect.X+1,m_weekRect.Y+4),m_pBrush);

    // 繪製時針
    float tem=(float)((float)x.wMinute/60);
    float fHour=x.wHour+tem;
    float sita=float(fHour*30);
    RotatePolygon(&g,hourPts,4,(float)sita); //計算時針旋轉角度並繪製

    // 繪製分針
    sita=float(x.wMinute*6);
    RotatePolygon(&g,mimPts,4,(float)sita);

    // 繪製秒針
    sita = float(x.wSecond*6);
    RotatePolygon(&g,scrPts,2,sita);

    // 繪製圓心
    m_pBrush->SetColor(Color(255,0,0,255));
    g.FillEllipse(m_pBrush,-6,-6,12,12);

    // 將記憶體dc中繪製的圖片複製到當前dc中
    BitBlt(hdc,0,0,(int)ps.rcPaint.right,(int)ps.rcPaint.bottom,hmdc,0,0,SRCCOPY);

    // 釋放記憶體點陣圖,記憶體dc
    SelectObject(hmdc,hOldMap);
    DeleteObject(hBitmap);
    DeleteObject(hmdc);

    EndPaint(m_hWnd,&ps);
}

相關文章