Win32 tehtäviä syventävät vastaus3

Mureakuha

Loikkaa: valikkoon, hakuun

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ä.


Alkuperäinen (c) Petteri Hämäläinen

Henkilökohtaiset työkalut