Tutorial 5: Více o textu

V tomto tutorialu budeme více experimentovat s vlastnostmi textu jako je font a barva.

Stáhněte si příklad : zde.

Teorie:

Systém barev ve Windows je založen na hodnotách RGB, R=červená, G=zelená, B=modrá. Jestliže chcete specifikovat barvu ve Windows, musíte svou požadovanou barvu určit pomocí těchto hlavních barev. Každá barva má rozsah od 0 do 255 (byte). Když například chcete čistě červenou barvu, použijete 255,0,0. Nebo když chcete čistě bílou, pak 255,255,255. Jak je vidět, získat barvu, kterou chcete je docela obtížné tímhle způsobem, protože musíte mít dobrý odhad na to, jak které barvy mixovat.
Pro barvu textu a pozadí se používá SetTextColor a SetBkColor. Obě funkce vyžadují handel ke kontextu zařízení a 32-bitovou RGB hodnotu. Struktura 32-bit RGB hodnoty je definovaná:

RGB_value struct
    neužitá   db 0
    modrá       db ?
    zelená     db ?
    červená        db ?
RGB_value ends

První byte není používán a měl by být nula. Pořadí zbývajících bytů je obrácené, tj. modrá, zelená, červená. My však tuto strukturu užívat nebudeme, protože je nepohodlné ji inicializovat. Vytvoříme se míto toho makro. Makro obdrží tři parametry, hodnoty pro: červenou, zelenou a modrou barevnou složku. To nám vyrobí požadovanou 32-bitovou RGB hodnotu a uloží ji do eax. Zde je makro:

RGB macro red,green,blue
    xor    eax,eax
    mov  ah,blue
    shl     eax,8
    mov  ah,green
    mov  al,red
endm

Můžete si ho uložit do hlavičkového souboru pro další použití.
Font můžete "vytvořit" pomocí CreateFont nebo CreateFontIndirect. Rozdíl mezi těmito funkcemi je ten, že CreateFontIndirect přijímá pouze jeden parametr: ukazatel na strukturu LOGFONT. CreateFontIndirect je více flexibilnější, zejména když potřebujete fonty měnit často ve vašem program. Pro ukázku ale vytvoříme jen jeden font a k tomu nám stačí CreateFont. Zavoláním této funkce získáme handel k fontu, který musíme vybrat do kontextu zařízení. Potom všechy API funkce pracující s textem použijí font, který jsem do kontextu zařízení vybrali.
 

Obsah:

.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
        xor eax,eax
        mov ah,blue
        shl eax,8
        mov ah,green
        mov al,red
endm

.data
ClassName db "SimpleWinClass",0
AppName  db "Naše Okno",0
TestString  db "Win32 assembly is great and easy!",0
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    200,200,50
        invoke SetTextColor,hdc,eax
        RGB    0,0,255
        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
 

Analysis:

        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 vytváří logický font, který je nejblíže daným parametrům a datům. Tato funkce má více parametrů než jakákoliv jiná funkce Windows. Vrací handel k logickému fontu, který použijeme v SelectObject funkci. Prozkoumáme parametry detailněji:

CreateFont proto nHeight:DWORD,\
                            nWidth:DWORD,\
                            nEscapement:DWORD,\
                            nOrientation:DWORD,\
                            nWeight:DWORD,\
                            cItalic:DWORD,\
                            cUnderline:DWORD,\
                            cStrikeOut:DWORD,\
                            cCharSet:DWORD,\
                            cOutputPrecision:DWORD,\
                            cClipPrecision:DWORD,\
                            cQuality:DWORD,\
                            cPitchAndFamily:DWORD,\
                            lpFacename:DWORD

nHeight   Požadovaná výška znaků. 0 znamená standardní velikost
nWidth   Požadovaná šířka znaků. Normálně by měla být 0, což umožní Windows spojit adekvátně výšku s šířkou. V mém případě dělá standardní šířka znaky nečitelné, takže jsem použil šířku 16.
nEscapement   Specifikuje orientaci znaků relativně k přechozímu znaku v desetinách stupně Normálně je 0. Nastavte 900 a znaky půjdou nahoru od prvního znaku, 1800 pro psaní pozpátku, nebo 2700, aby každý znak byl napsán zhora dolů.
nOrientation   Určuje o kolik stupňů se má každý znak otočit v desetinách stupně. Nastavte 900 a znaky budou ležet na zádech, 1800 pro převrácení znaků apod.
nWeight   Nastavuje tloušťku čáry znaku. Windows definuje tyto velikosti:

cItalic   0 pro normální, jakákoliv jiná hodnota pro kursivu.
cUnderline   0 pro normální, jakákoliv další hodnota pro podtržené znaky.
cStrikeOut   0 pro normální, jakákoliv další hodnota pro přeškrtnuté znaky.
cCharSet  Znaková sada fontu. Normálně by měla být OEM_CHARSET, což dovoluje Windowsům vybrat font, který je odvislý od operačního systému.
cOutputPrecision  Určuje, do jaké míry musí vybraný font splňovat charakteristiky, které požadujeme. Normálně by mělo být OUT_DEFAULT_PRECIS, které určí standardní způsob chování.
cClipPrecision  Určuje, jak ořezat znaky, které jsou částečně mimo obdélník. Měli by jste si vystačit s CLIP_DEFAULT_PRECIS, což určuje standarní chování.
cQuality  Určuje kvalitu výstupu. Ta určuje jak opatrně se má GDI pokoušet spojit atributy logického fontu se skutečným fyzickým fontem. Jsou tři možnosti: DEFAULT_QUALITY, PROOF_QUALITY and  DRAFT_QUALITY.
cPitchAndFamily  Určuje rozmezí a rodinu fontu. Hodnoty musíte kombinovat pomocí "or".
lpFacename  Ukazatel na nulou ukončený řetězec, který určuje druh písma fontu.

Popis výše není zdaleka úplný, další informace hledejte ve Win32 API referencích.

        invoke SelectObject, hdc, eax
        mov    hfont,eax

Po té co získáme handel k logickému fontu, musíme ho použít k výběr fontu do kontextu zařízení pomocí funkce SelectObject. SelectObject vkládá nové GDI objekty jako pera, štětce a fonty do kontextu zařízení. Vrací handel k nahrazenému objektu, který bychom si měli schovat pro další použití. Po zavolání SelectObject bude každá funkce pracující s textem používat font, který jsme právě zvolili do kontextu.

        RGB    200,200,50
        invoke SetTextColor,hdc,eax
        RGB    0,0,255
        invoke SetBkColor,hdc,eax

Použijte RGB makro pro vytvoření 32-bitové RGB hodnoty jako parametr pro SetColorText a SetBkColor.

        invoke TextOut,hdc,0,0,ADDR TestString,SIZEOF TestString

Poté zavoláme TextOut funkci, která nakreslí text do naší klientské oblasti. Text bude vykreslen fontem a barvou, kterou jsme předtím určili.

        invoke SelectObject,hdc, hfont

Když už náš font nepotřebujeme, měli bychom vybrat starý font zpět do kontextu zařízení.


[Iczelion's Win32 Assembly HomePage]
Překlad Shaldan 2006, fx.s@seznam.cz - při četbě a využívání nových poznatků z četby opravdu za nic neručím :))