Win32 tehtäviä syventävät vastaus3
Mureakuha
Tehtävä:
Kirjoita kello. Piirrä kellotaulu ja viisarit LineTo()-funktiolla. Varaa kerran sekunnissa toimiva Timer-kontrolli ja kutsu sieltä WM_PAINT sanomaa, jolloin Windows itse pyyhkii vanhat viisarit pois. Ohjelman täytyy osata skaalata viisarit oikean kokoisiksi riippumatta ikkunan koosta. Kellotaulun ympyrämuodon kaava voidaan laskea sin()- ja cos()-funktioilla. Kun origo on vasemmassa yläkulmassa, kaavan koordinaatit ovat muotoa,
- Keskipiste: ikkunan_leveys/2-ikkunan_korkeus/2
- X-koordinaatti: ikkunan_leveys/2+sin(x)*haluttu_etäisyys_keskipisteestä
- Y-koordinaatti: ikkunan_korkeus/2-cos(x)*haluttu_etäisyys_keskipisteestä
jossa x on haluttu kulma radiaaneissa (00:00 on nolla ja 12:00 on 2*PII radiaania).
#include <windows.h> #include <math.h> // sin() ja cos() HINSTANCE hInstance ; // käynnistyvän ohjelman kahva LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static char szAppName[] = "Kello" ; // 'ohjelman nimi' HWND hwnd ; MSG msg ; WNDCLASSEX wndclass ; wndclass.cbSize = sizeof (wndclass) ; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH) COLOR_WINDOW ; wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ; wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION) ; RegisterClassEx (&wndclass) ; hwnd = CreateWindow (szAppName, "Kello", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, NULL, NULL, hInstance, NULL) ; if (!SetTimer (hwnd, 1, 1000, NULL)) // Ajastimen varaus, toimii kerran sekunnissa { MessageBox (hwnd, "Ei vapaita ajastimia!", "Virhe", MB_ICONEXCLAMATION | MB_OK) ; return FALSE ; // ajastimet loppu, ohjelma lopetetaan } ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; // ikkunan päivitys while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ; } LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { static HPEN hPen ; // luotavan kynän kahva static SYSTEMTIME aika ; // aika-struktuuriin tallennetaan kellonaika HDC hdc ; // piirtopinnan kahva PAINTSTRUCT ps ; // PAINTSTRUCT-struktuuria käytetään BeginPaint()-funktiossa RECT rect; // RECT-struktuuria käytetään GetClientRect()-funktiossa POINT pt ; // POINT-struktuuria käytetään LineTo()-funktiossa switch (iMsg) // sanomien käsittelyrakenne { case WM_CREATE : // initialisaatiosanoman käsittely hPen = CreatePen (PS_SOLID, 2, RGB(0, 0, 0)); // luodaan 2 pistettä paksu musta kynä return 0 ; // pois ikkunaproseduurista case WM_PAINT : { hdc = BeginPaint (hwnd, &ps) ; GetClientRect (hwnd, &rect); // kysytään ruudun koko ja talletetaan se rect-struktuuriin SelectObject (hdc, GetStockObject(BLACK_PEN)) ; //BLACK_PEN on musta varastokynä, piirretään sillä kellotaulu for (double x=0; x<6.2832; x=x+0.5236) // sin() ja cos() käyttävät radiaaneja, 6.2832 == 2*PI { MoveToEx (hdc, rect.right/2+int(sin(x)*rect.right*0.45), rect.bottom/2-int(cos(x)*rect.bottom*0.45), &pt) ; // Piirretään kellotaulu LineTo (hdc, rect.right/2+int(sin(x)*rect.right*0.4), rect.bottom/2-int(cos(x)*rect.bottom*0.4)) ; } SelectObject (hdc, hPen) ; //hPen on paksumpi kuin BLACK_PEN, piirretään sillä viisarit MoveToEx (hdc, rect.right/2, rect.bottom/2, &pt) ; // LineTo() vaatii pt-struuriin viivan alkupisteen LineTo (hdc, rect.right/2+int(sin(6.2832*aika.wSecond/60)*rect.right*0.34), rect.bottom/2-int(cos(6.2832*aika.wSecond/60)*rect.bottom*0.34)) ; // Sekunnit MoveToEx (hdc, rect.right/2, rect.bottom/2, &pt) ; LineTo (hdc, rect.right/2+int(sin(6.2832*aika.wMinute/60)*rect.right*0.3), rect.bottom/2-int(cos(6.2832*aika.wMinute/60)*rect.bottom*0.3)) ; // Minuutit MoveToEx (hdc, rect.right/2, rect.bottom/2, &pt) ; LineTo (hdc, rect.right/2+int(sin(6.2832*aika.wHour/12)*rect.right*0.25), rect.bottom/2-int(cos(6.2832*aika.wHour/12)*rect.bottom*0.25)) ; // Tunnit EndPaint (hwnd, &ps) ; return 0; } case WM_TIMER : GetLocalTime (&aika) ; // haetaan kellonaika aika-struktuuriin InvalidateRect(hwnd, NULL, TRUE); // asetetaan koko ikkuna epäkelvoksi, Windows generoi WM_PAINT sanoman return 0 ; case WM_DESTROY : // lopetussanoman käsittely KillTimer (hwnd, 1) ; // poistetaan Timer käytöstä ennen lopetusta, ei tuhlaa resursseja DeleteObject (hPen) ; // poistetaan luotu kynä, ei tuhlata resursseja PostQuitMessage (0) ; // lopetusviesti Windowsille return 0 ; } return DefWindowProc (hwnd, iMsg, wParam, lParam) ; // sanomien oletuskäsittely }
Tämän dokumentin kopiointi, levittäminen sekä muokkaaminen on sallittua GNU Free Documentation Licensen version 1.2 tai uudemman Free Software Foundationin julkaiseman version mukaisesti, ilman muuttumattomuuslauseketta tai kansitekstejä. Tätä koskee vastuuvapaus.
Kopio lisenssistä (englanniksi) löytyy täältä.
Kopio lisenssistä (englanniksi) löytyy täältä.
Alkuperäinen (c) Petteri Hämäläinen
