Rozdział V - Więcej na temat tekstu


Poeksperymentujemy z atrybutami tekstu, tj. z czcionką i kolorem.

 

obrazek

 

Załaduj sobie plik źródłowy tego przykładu {z tego archiwum}.

 

Teoria

System kolorów w Windows oparty jest na wartościach RGB, R=czerwony (red), G=zielony (green), B=niebieski (blue). Jeśli chcesz określić kolor, to musisz go przetworzyć na te trzy podane kolory główne. Każda wartość koloru posiada zakres od 0 do 255 (wartość bajtowa). Na przykład dla czysto czerwonego koloru powinieneś użyć 255,0,0. A czysty biały kolor wymaga wartości RGB równej 255,255,255. Jak widać z powyższych przykładów określenie potrzebnego koloru w tym systemie jest bardzo trudne, ponieważ musisz posiadać dobre wyczucie mieszania i doboru kolorów.

Kolor tekstu i tła ustawiamy wywołując odpowiednio funkcje SetTextColor oraz SetBkColor i przekazując im jako parametr uchwyt kontekstu urządzenia oraz 32 bitową wartość RGB. Struktura 32 bitowej wartości RGB jest następująca:

 

RGB_value STRUCT
    unused DB 0 
    blue   DB ? 
    green  DB ? 
    red    DB ? 
RGB_value ENDS


Zwróć uwagę, iż pierwszy bajt nie jest używany i powinien mieć wartość 0. Kolejność pozostałych 3 bajtów jest odwrócona, tj. niebieski (blue), zielony (green) oraz czerwony (red). Jednakże w naszym programie nie skorzystamy z tej struktury, ponieważ jest ona kłopotliwa do inicjalizacji i użycia. Zamiast tego utworzymy makro. Makro otrzyma wartości trzech parametrów: red, green oraz blue. Utworzy pożądaną, 32-bitową wartość RGB i umieści ją w rejestrze eax. Makro jest następujące:

 

RGB MACRO red, green, blue
    mov eax, red OR (green SHL 8) OR (blue SHL 16)
ENDM


Czcionkę możesz "utworzyć" wywołując CreateFont lub CreateFontIndirect. Różnicą pomiędzy tymi dwoma funkcjami jest to, iż CreateFontIndirect otrzymuje tylko jeden parametr - wskazanie logicznej struktury czcionki LOGFONT. Z tych dwóch funkcji CreateFontIndirect jest bardziej uniwersalna, szczególnie gdy twój program musi często zmieniać czcionki. Jednakże w naszym przykładzie "utworzymy" tylko jedną czcionkę dla demonstracji, zatem możemy zastosować CreateFont. Po wywołaniu tej funkcji zwróci ona uchwyt czcionki, który musisz następnie wstawić do kontekstu urządzenia. Po wykonaniu tej operacji wszystkie funkcje API będą używały wybranej czcionki.

Treść

.386

.MODEL FLAT, STDCALL

OPTION CASEMAP:NONE

WinMain PROTO :DWORD, :DWORD, :DWORD, :DWORD

INCLUDE    \masm32\include\windows.inc
INCLUDE    \masm32\include\user32.inc
INCLUDE    \masm32\include\kernel32.inc
INCLUDE    \masm32\include\gdi32.inc
INCLUDELIB \masm32\lib\user32.lib
INCLUDELIB \masm32\lib\kernel32.lib
INCLUDELIB \masm32\lib\gdi32.lib

RGB MACRO red, green, blue
    mov eax, red or (green shl 8) or (blue shl 16)
ENDM

.DATA

ClassName  DB "SimpleWinClass",0
AppName    DB "Okienko z tekstem",0
TestString DB "Asembler Win32 jest prosty!"
FontName   DB "script",0

.DATA?

hInstance   HINSTANCE ?
CommandLine LPSTR     ?

.CODE

start:
    INVOKE GetModuleHandle, NULL
    mov    hInstance, eax
    INVOKE GetCommandLine
    mov    CommandLine, eax
    INVOKE WinMain, hInstance, NULL, CommandLine, SW_SHOWDEFAULT
    INVOKE ExitProcess, eax

WinMain PROC hInst:     HINSTANCE,\
             hPrevInst: HINSTANCE,\
             CmdLine:   LPSTR,\
             CmdShow:   DWORD

LOCAL wc:   WNDCLASSEX
LOCAL msg:  MSG
LOCAL hwnd: HWND

    mov    wc.cbSize, SIZEOF WNDCLASSEX
    mov    wc.style, CS_HREDRAW or CS_VREDRAW
    mov    wc.lpfnWndProc, OFFSET WndProc
    mov    wc.cbClsExtra, NULL
    mov    wc.cbWndExtra, NULL
    push   hInst
    pop    wc.hInstance
    mov    wc.hbrBackground, COLOR_WINDOW+1
    mov    wc.lpszMenuName, NULL
    mov    wc.lpszClassName, OFFSET ClassName
    INVOKE LoadIcon, NULL, IDI_APPLICATION
    mov    wc.hIcon, eax
    mov    wc.hIconSm, eax
    INVOKE LoadCursor, NULL, IDC_ARROW
    mov    wc.hCursor, eax   
    INVOKE RegisterClassEx, ADDR wc
    INVOKE CreateWindowEx, NULL, ADDR ClassName, ADDR AppName,\
                           WS_OVERLAPPEDWINDOW,\
                           CW_USEDEFAULT, CW_USEDEFAULT,\
                           CW_USEDEFAULT, CW_USEDEFAULT,\
                           NULL, NULL, hInst, NULL
    mov  hwnd, eax
    INVOKE ShowWindow, hwnd, SW_SHOWNORMAL
    INVOKE UpdateWindow, hwnd

    .WHILE TRUE
        INVOKE GetMessage, ADDR msg, NULL, 0, 0
        .BREAK .IF (!eax)
        INVOKE TranslateMessage, ADDR msg
        INVOKE DispatchMessage, ADDR msg
    .ENDW

    mov eax, msg.wParam
    ret

WinMain ENDP

WndProc PROC hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

LOCAL hdc:   HDC
LOCAL ps:    PAINTSTRUCT
LOCAL hfont: HFONT

    .IF uMsg==WM_DESTROY
        INVOKE PostQuitMessage, NULL
    .ELSEIF uMsg==WM_PAINT
        INVOKE BeginPaint, hWnd, ADDR ps
        mov    hdc, eax
        INVOKE CreateFont,24, 16, 0, 0, 400, 0, 0, 0,\
                          OEM_CHARSET, OUT_DEFAULT_PRECIS,\
                          CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,\
                          DEFAULT_PITCH or FF_SCRIPT, ADDR FontName

        INVOKE SelectObject, hdc, eax
        mov    hfont, eax
        RGB    255,255,0
        INVOKE SetTextColor, hdc, eax
        RGB    0,127,127
        INVOKE SetBkColor, hdc, eax
        INVOKE TextOut, hdc, 0, 0, ADDR TestString, SIZEOF TestString
        INVOKE SelectObject, hdc, hfont
        INVOKE EndPaint, hWnd, ADDR ps
    .ELSE
        INVOKE DefWindowProc, hWnd, uMsg, wParam, lParam
        ret
    .ENDIF

    xor eax, eax
    ret

WndProc ENDP

END start 

Analiza

    INVOKE CreateFont,24, 16, 0, 0, 400, 0, 0, 0,\
                      OEM_CHARSET, OUT_DEFAULT_PRECIS,\
                      CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,\
                      DEFAULT_PITCH OR FF_SCRIPT, ADDR FontName


CreateFont
tworzy logiczną czcionkę najbardziej zbliżoną do podanych parametrów na podstawie dostępnych zasobów czcionek systemu. Funkcja ta ma więcej parametrów niż jakakolwiek inna funkcja w systemie Windows. Zwraca ona uchwyt do logicznej czcionki, który ma być użyty przez funkcję SelectObject.

Przeanalizujemy szczegółowo jej parametry:


CreateFont PROTO nHeight:            DWORD,\ 
                 nWidth:             DWORD,\ 
                 nEscapement:        DWORD,\ 
                 nOrientation:       DWORD,\ 
                 fnWeight:           DWORD,\ 
                 fdwItalic:          DWORD,\ 
                 fdwUnderline:       DWORD,\ 
                 fdwStrikeOut:       DWORD,\ 
                 fdwCharSet:         DWORD,\ 
                 fdwOutputPrecision: DWORD,\ 
                 fdwClipPrecision:   DWORD,\ 
                 fdwQuality:         DWORD,\ 
                 fdwPitchAndFamily:  DWORD,\ 
                 lpszFace:           DWORD 
FW_DONTCARE   EQU   0
FW_THIN       EQU 100
FW_EXTRALIGHT EQU 200
FW_ULTRALIGHT EQU 200
FW_LIGHT      EQU 300
FW_NORMAL     EQU 400
FW_REGULAR    EQU 400
FW_MEDIUM     EQU 500
FW_SEMIBOLD   EQU 600
FW_DEMIBOLD   EQU 600
FW_BOLD       EQU 700
FW_EXTRABOLD  EQU 800
FW_ULTRABOLD  EQU 800
FW_HEAVY      EQU 900
FW_BLACK      EQU 900

Opis podany powyżej nie jest w żaden sposób wyczerpujący. Więcej szczegółów znajdziesz w pliku pomocy dla funkcji API Win32.


    INVOKE SelectObject, hdc, eax 
    mov    hfont, eax


Po otrzymaniu uchwytu do logicznej czcionki musimy użyć go do ustawienia tej czcionki w kontekście urządzenia przez wywołanie funkcji SelectObject. Funkcja ta umieszcza nowe obiekty GDI takie jak pióra, pędzle i czcionki w kontekście urządzenia, aby były używane przez funkcje GDI. Zwraca ona uchwyt zastąpionego obiektu, który musisz zachować dla przyszłego wywołania SelectObject. Po tym wywołaniu każda funkcja wyprowadzająca tekst na ekran będzie używała nowej czcionki ustawionej w kontekście urządzenia.


    RGB    255,255,0
    INVOKE SetTextColor, hdc, eax
    RGB    0,127,127
    INVOKE SetBkColor, hdc, eax


Użyj makra RGB do utworzenia 32-bitowej wartości RGB do zastosowania jako parametr dla funkcji SetTextColor oraz SetBkColor.


    INVOKE TextOut, hdc, 0, 0, ADDR TestString, SIZEOF TestString


Do narysowania tekstu na obszarze roboczym okna wywołaj funkcję TextOut. Tekst będzie posiadał czcionkę oraz kolor określone wcześniej.


    INVOKE SelectObject, hdc, hfont

 

Gdy zakończymy pracę z daną czcionką, powinniśmy odtworzyć poprzednią czcionkę w kontekście urządzenia. Zawsze powinieneś odtworzyć obiekt, który zastąpiłeś w kontekście urządzenia.

 

Dodatek w Pascalu

Ta sama aplikacja w Pascalu:

 

{********************************
**  I Liceum Ogólnokształcące  **
**           w Tarnowie        **
**       mgr Jerzy Wałaszek    **
********************************}

program MoreText;

uses Windows;

function RGB(R,G,B : integer) : UINT;
begin
  RGB := R or (G shl 8) or (b shl 16);
end;

function WndProc(h:HWND;uMsg:UINT;wP:WPARAM;lP:LPARAM) : longint;
const
  OurText  = 'FreePascal jest prosty';
  FontName : string = 'script';
var
  HDevCnt: HDC;
  ps     : PAINTSTRUCT;
  hf     : HFONT;
  r      : RECT;

begin
  WndProc := 0;
  case uMsg of
    WM_DESTROY: PostQuitMessage(0);
    WM_PAINT   : begin
                  HDevCnt := BeginPaint(h,ps);
                  hf := SelectObject(HDevCnt,
                        CreateFont(24,16,0,0,400,0,0,0,
                                   OEM_CHARSET,OUT_DEFAULT_PRECIS,
                                   CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,
                                   DEFAULT_PITCH or FF_SCRIPT,@FontName));
                  SetTextColor(HDevCnt,RGB(255,255,0));
                  SetBkColor(HDevCnt,RGB(0,127,127));
                  TextOut(HDevCnt,0,0,OurText,Length(OurText));
                  SelectObject(HDevCnt, hf);
                  EndPaint(h,ps);
    else  WndProc := DefWindowProc(h,uMsg,wP,lP);
  end;
end;

function WinMain(hI,hPI:HINST;CmdLine:LPSTR;cmdShow:longint) : longint;
const 
  ClassName = 'SimpleWinClass';
var
  wc : WndClassEx;
  ms : msg;
  h  : HWnd;
begin
  wc.cbSize        := SizeOf(WndClassEx);
  wc.style         := CS_HREDRAW or CS_VREDRAW;
  wc.lpfnWndProc   := @WndProc;
  wc.cbClsExtra    := 0;
  wc.cbWndExtra    := 0;
  wc.hInstance     := hI;
  wc.hbrBackground := COLOR_WINDOW + 1;
  wc.lpszMenuName  := 0;
  wc.lpszClassName := ClassName;
  wc.hIcon         := LoadIcon(0,IDI_APPLICATION);
  wc.hIconSm       := wc.hIcon;
  wc.hCursor       := LoadCursor(0,IDC_ARROW);
  RegisterClassEx(wc);
  h := CreateWindowEx(0,ClassName,'Nasze okno z tekstem',
                      WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,
                      CW_USEDEFAULT,CW_USEDEFAULT,0,0,hI,0);
  ShowWindow(h,CmdShow);
  UpdateWindow(h);
  while GetMessage(ms,0,0,0) do
  begin
    TranslateMessage(ms);
    DispatchMessage(ms);
  end;
  WinMain := ms.wParam;
end;

begin
  ExitProcess(WinMain(GetModuleHandle(0),0,0,SW_SHOWDEFAULT));
end.

 

Autorem kursu jest Iczelion. Kurs programowania Windows znalazł się na serwerze I LO w Tarnowie za pisemną zgodą autora.
Tłumaczenie z języka angielskiego, opracowanie HTML i konwersję przykładów programów wykonał mgr Jerzy Wałaszek.


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

©2024 mgr Jerzy Wałaszek

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

Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl

W artykułach serwisu są używane cookies. Jeśli nie chcesz ich otrzymywać,
zablokuj je w swojej przeglądarce.
Informacje dodatkowe