P021 - Pisanie tekstu w oknie
Programy uruchomiono w środowisku Bloodshed Dev-C++ 4.9.9.2
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//--------------------------
// Koło informatyczne 2006/7
//--------------------------
// Program: P021-01
//--------------------------

#include <windows.h>

char ClassName[ ] = "SimpleTxWinClass";

// Procedura wywoływana przez Windows, gdy pojawi się wiadomość do obsłużenia przez okno
//--------------------------------------------------------------------------------------

LRESULT CALLBACK WndProc(HWND h, UINT uMsg , WPARAM wP, LPARAM lP)
{
  switch(uMsg)
  {
    case WM_DESTROY : 

      PostQuitMessage(0);
      break;  

// W procedurze okna obsługujemy wiadomość WM_PAINT, która jest wysyłana przy konieczności
// przerysowania obszaru roboczego okna.

    case WM_PAINT : 

      HDC         hdc;  // uchwyt kontekstu graficznego
      PAINTSTRUCT pps;  // struktura parametrów rysowania
      RECT        r;    // prostokąt obejmujący obszar roboczy okna

      hdc = BeginPaint(h, &pps);
      GetClientRect(h, &r);
      DrawText(hdc, "Witaj w świecie MS-Windows",-1, &r, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
      EndPaint(h, &pps);
      break;

    default:

      return DefWindowProc(h, uMsg, wP, lP);
  }
  return 0;
}

// Punkt startowy programu
//------------------------
        
int WINAPI WinMain (HINSTANCE hinst, HINSTANCE hprevinst, LPSTR cmdLine, int cmdShow)
{
  WNDCLASSEX wc;
  MSG        ms;
  HWND       h;

  wc.cbSize        = sizeof(WNDCLASSEX);
  wc.style         = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc   = WndProc;
  wc.cbClsExtra    = wc.cbWndExtra = 0;
  wc.hInstance     = hinst;
  wc.hbrBackground = (HBRUSH) COLOR_WINDOW;
  wc.lpszMenuName  = NULL;
  wc.lpszClassName = ClassName;
  wc.hIcon         = wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
  wc.hCursor       = LoadCursor(NULL, IDC_ARROW);

  if(!RegisterClassEx(&wc)) return 0;
  h = CreateWindowEx(0, ClassName,"Piszemy w naszym oknie", WS_OVERLAPPEDWINDOW,
                     CW_USEDEFAULT, CW_USEDEFAULT, 300, 200, 0, 0, hinst, 0);
  ShowWindow(h, cmdShow);
  UpdateWindow(h);
  while(GetMessage(&ms, NULL, 0, 0))
  {
    TranslateMessage(&ms);
    DispatchMessage(&ms);
  }
  return ms.wParam;
}
Efekt uruchomienia programu

Podane tutaj informacje pochodzą z bazy wiedzy dla systemu Windows stworzonej przez firmę Microsoft i udostępnionej darmowo w Internecie pod tym adresem:

http://msdn.microsoft.com

       Wyjaśnienie

Większość kodu programu jest identyczna z wersją P020. Zatem opiszę tylko nowe elementy.

Program w systemie Windows nie może sobie tak po prostu coś narysować na ekranie. Ekran jest zasobem współdzielonym, zatem korzystanie z niego musi się odbywać wg ściśle określonych zasad. Okienko, po którym chcemy rysować może znajdować się w różnych stanach (np. może być zminimalizowane lub częściowo przykryte innym oknem itp.). Dlatego przy operacjach graficznych należy bezwzględnie wykorzystywać funkcje jądra graficznego GDI (ang. Graphic Device Interface - interfejs grafiki).

Jeśli chcemy coś narysować na obszarze roboczym okienka (ang. client area), najpierw musimy poprosić system Windows o udostępnienie dla tego obszaru uchwytu odpowiedniego kontekstu graficznego (ang. DC - device context).  Uchwyt kontekstu graficznego identyfikuje pewną wewnętrzną strukturę danych w systemie Windows, w której są umieszczone różne parametry graficzne. Uchwyt DC można otrzymać na kilka sposobów. W naszym programie wykorzystujemy do tego celu funkcję:

HDC BeginPaint(HWND hwnd,  LPPAINTSTRUCT lpPaint);
HDC - typ danych określający uchwyt do kontekstu graficznego
HWND - typ danych dla uchwytu okna
LPPAINTSTRUCT - długi wskaźnik struktury PAINTSTRUCT
 
hwnd - uchwyt okna, po którym będziemy rysować
lpPaint - wskaźnik struktury PAINTSTRUC, w której funkcja BeginPaint zapisze informacje graficzne. Struktura ta posiada następującą definicję:
typedef struct tagPAINTSTRUCT
{ 
  HDC  hdc; 
  BOOL fErase; 
  RECT rcPaint; 
  BOOL fRestore; 
  BOOL fIncUpdate; 
  BYTE rgbReserved[32]; 
} PAINTSTRUCT, *PPAINTSTRUCT; 
hdc - uchwyt kontekstu graficznego urządzenia, które ma być użyte do rysowania (np. ekran, drukarka)
fErase - określa, czy przy rysowaniu musi być wymazane tło obszaru. Wartość tego pola jest niezerowa, jeśli aplikacja powinna wymazać tło. Obowiązek ten spoczywa na aplikacji, jeśli klasa okna została utworzona bez określenia pędzla tła.
rcPaint - określa strukturę RECT definiującą współrzędne narożników (lewy górny i prawy dolny) prostokąta, w którym konieczne jest malowanie. Prostokąt ten nie jest obszarem roboczym okna, lecz jego fragmentem, który musi być przerysowany. Współrzędne są określone względem lewego górnego narożnika obszaru roboczego okna.
fRestore
fIncUpdate
rgbReserved
- pola zarezerwowane do wewnętrznego użytku przez system Windows

Jeśli wywołanie funkcji się powiedzie, to zwrócony zostanie uchwyt kontekstu graficznego, który należy zachować w osobnej zmiennej, ponieważ będzie niezbędny przy operacjach graficznych na okienku. Jeśli wystąpi błąd, to funkcja zwróci wartość NULL.

Po pobraniu uchwytu kontekstu graficznego ustalamy obszar rysowania. W naszym programie nie bawimy się w szczegóły i pobieramy do struktury RECT współrzędne całego obszaru roboczego okna przy pomocy funkcji GetClientRect. W rzeczywistości w PAINTSTRUC.rcPaint system Windows umieszcza prostokąt obejmujący ten fragment obszaru roboczego okna, który uległ zmianie (np. przesunięto zakrywające go inne okno) i powinien zostać przerysowany (taki prostokąt nosi nazwę nieaktualnego - ang. invalid rectangle). Wykorzystanie tej informacji jest czasami dużo efektywniejsze od przerysowywania całego obszaru roboczego okna, lecz również i trudniejsze, gdyż musimy odpowiednio przeliczać położenia wszystkich obiektów graficznych.

Do wyrysowania tekstu na obszarze roboczym wykorzystujemy funkcję:

int DrawText(HDC hDC, LPCTSTR lpString, int nCount, LPRECT lpRect, UINT uFormat);
hDC - uchwyt kontekstu graficznego
lpString - wskaźnik tekstu do wyświetlenia.
nCount - określa liczbę znaków w wyświetlanym tekście. Jeśli parametr nCount ma wartość -1, to tekst musi być zakończony znakiem o kodzie 0.
lpRect - wskaźnik struktury RECT zawierającej współrzędne prostokąta, w którym tekst ma zostać sformatowany.
typedef struct _RECT
{ 
  LONG left; 
  LONG top; 
  LONG right; 
  LONG bottom; 
} RECT, * PRECT; 
left - współrzędna x lewego górnego narożnika
top - współrzędna y lewego górnego narożnika
right - współrzędna x prawego dolnego narożnika
bottom - współrzędna y prawego dolnego narożnika
uFormat - określa sposób formatowania tekstu. Parametr ten może być złożony (za pomocą operatora | ) z poniższych stałych (opisujemy tylko niektóre wartości, resztę znajdziesz na stronach Microsoftu):
DT_BOTTOM - wyrównuje tekst do spodu prostokąta. Wartość ta jest wykorzystywana tylko po dołączeniu stałej DT_SINGLELINE.
DT_CENTER - wyśrodkowuje tekst w poziomie w obrębie prostokąta.
DT_END_ELLIPSIS - jeśli końcówka wiersza nie mieści się w prostokącie, zostaje obcięta i zastąpiona trójkropkiem.
DT_EXPANDTABS - rozwija znaki tabulacji. Standardową liczbą znaków dla tabulacji jest osiem.
DT_LEFT - wyrównuje tekst do lewej krawędzi prostokąta
DT_NOCLIP - rysuje tekst bez obcinania do rozmiaru prostokąta - opcja ta nieco przyspiesza działanie funkcji DrawText.
DT_RIGHT - wyrównuje tekst do prawej krawędzi prostokąta
DT_SINGLELINE - wyświetla tekst w postaci jednego wiersza - znaki końca wiersza i końca strony nie powodują złamania wiersza.
DT_TOP - wyrównuje tekst do górnej krawędzi prostokąta
DT_VCENTER - wyśrodkowuje tekst w pionie. Wartość ta jest używana tylko razem z wartością DT_SINGLELINE.
DT_WORDBREAK - automatycznie przenosi wyrazy do następnego wiersza, jeśli wykraczają poza krawędź prostokąta przekazanego w parametrze lpRect. Wiersz jest również łamany znakami końca wiersza i końca strony.

Przed zakończeniem obsługi wiadomości WM_PAINT musimy zwolnić uchwyt kontekstu graficznego. W tym celu wywołujemy funkcję EndPaint().



List do administratora Serwisu Edukacyjnego Nauczycieli I LO

Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:
Uwaga: ← tutaj wpisz wyraz  ilo , inaczej list zostanie zignorowany

Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048

 

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień szeroko opisywanych w podręcznikach.



   I Liceum Ogólnokształcące   
im. Kazimierza Brodzińskiego
w Tarnowie

©2017 mgr Jerzy Wałaszek

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.