19. Szöveg és fontok (Text and Fonts)
2014.06.22. 16:52
Példa: font_one
Fontok betöltése
Ha valaki esetleg nem tudná a font az a betűtípust jelenti. Beleértve a külalakot, hogy dőlt vagy félkövér, a színét, és méretét is. Most jó sok magyarázat fog következni, ezért a fordítás hitelessége erősen kérdéses. Kérlek fenntartással olvasd! - ford. -
A Win32 GDI figyelemre méltó hozadéka a sok betűtípus, stílus, nyelv, és karakterkészlet. Ez azzal jár, hogy a CreateFont() összesen 14 paramétert vár (magasság, stílus, család, stb)! Ijesztő!
Szerencsére ez annyira nem is fáj, mert sokszor használhatjuk az alapértelmezett értékeket, ami egyszerűen 0, vagy NULL. Ilyenkor a rendszerszintű beállítást veszi alapul.
A CreateFont() egy HFONT handlert hoz létre. A GetObject() egy LOGFONT struktúrát tölt fel, pont úgy, ahogyan a HBITMAP-ból egy BITMAP struktúrát.
A LOGFONT mezői megegyeznek a CreateFont() paramétereivel, és egy létező LOGFONT struktúra segítségével közvetlenül létrehozhatunk fontot. Ehhez a CreateFontIndirect()-et használhatjuk. Ez akkor hasznos, ha egy létező font handleréből akarunk új fontot létrehozni, hogy csak pár dologban térjen el az eredetitől. A GetObject() használatával kitöltjük a LOGFONT-ot, megváltoztatjuk amit akarunk, majd létrehozzuk az új fontot a CreateFontIndirect() segítségével.
HFONT hf; HDC hdc; long lfHeight; hdc = GetDC(NULL); lfHeight = -MulDiv(12, GetDeviceCaps(hdc, LOGPIXELSY), 72); ReleaseDC(NULL, hdc); hf = CreateFont(lfHeight, 0, 0, 0, 0, TRUE, 0, 0, 0, 0, 0, 0, 0, "Times New Roman"); if(hf) { DeleteObject(g_hfFont); g_hfFont = hf; } else { MessageBox(hwnd, "Font creation failed!", "Error", MB_OK | MB_ICONEXCLAMATION); }
Ezzel a kóddal létrehozzuk a példa képen látható fontot. Ez a Times New Roman, 12 pont magas, dőlt típus. A dőlt flag a CreateFont() hatodik paramétere, amit TRUE -ra állítottunk. A használandó font neve az utolsó paraméter.
Van egy kis trükk a dologban. Amikor az emberek betűtípussal dolgoznak, akkor képpontban akarják megadni a méretét. 10-es méret, 12-es méret stb. Na ez az, amit a CreateFont() nem fogad el! Ő ugyanis logikai egységet vár, ami eltér a képernyőnk a nyomtatónk között, de két nyomtató és két képernyő között is eltérő lehet. Az egyes eszközök felbontása ugyanis nagyon nagy szórást mutathat. A nyomtatók tudnak 600, 1200 képpontot inch-enként, míg a monitor jó ha 200-at. Ha ugyanazt a betűméretet használnánk nyomtatóhoz és monitorhoz is, valószínűleg ki sem tudnánk olvasni az egyes betűket!
Mindössze annyi dolgunk van, hogy a pont méretből konvertálunk a készülég logikai egységébe. Jelen esetben a készülék a képernyő, így elkérjük a képernyő HDC-jét. A GetDeviceCaps() adja meg a logikai képpontok számát inch-enként. A MulDiv() szoroz, oszt, és máris megvan a helyes logikai egység, amit a CreateFont() is elfogad.
Alap betűkészlet
Amikor először hívjuk a GetDC()-t hogy megkapjuk az ablakunk HDC-jét, akkor a rendszer alap betűtípusa van kiválasztva, ami nem túl esztétikus. A legegyszerűbb út egy működő fonthoz, ha a GetStockObject()-et meghívjuk, és kiválasztjuk a DEFAULT_GUI_FONT-ot. Így elkerüljük a CreateFont() maceráit. Ez egy rendszer objektum, és tetszőleges számban meghívható, nem kell memória szivárgástól tartani. Meghívhatjuk a DeleteObject()-et ami nem csinál semmit, nem kell követni a CreateFont() vagy GetStockObject()-et mielőtt megpróbáljuk felszabadítani.
Szöveg rajzolása
Most hogy van egy jó kis fontunk, hogyan tesszük ki a szöveget a képernyőre? Ez feltételezi hogy nem Edit vagy Stactic vezérlőre akarunk írni.
Alap lehetőségek a TextOut(), vagy DrawText(). A TextOut() egyszerűbb, de kevesebbet is tud. Nem csinál szövegtörést és igazítást.
char szSize[100]; char szTitle[] = "These are the dimensions of your client area:"; HFONT hfOld = SelectObject(hdc, hf); SetBkColor(hdc, g_rgbBackground); SetTextColor(hdc, g_rgbText); if(g_bOpaque) { SetBkMode(hdc, OPAQUE); } else { SetBkMode(hdc, TRANSPARENT); } DrawText(hdc, szTitle, -1, prc, DT_WORDBREAK); wsprintf(szSize, "{%d, %d, %d, %d}", prc->left, prc->top, prc->right, prc->bottom); DrawText(hdc, szSize, -1, prc, DT_SINGLELINE | DT_CENTER | DT_VCENTER); SelectObject(hdc, hfOld);
Első dolog, hogy a SelectObject() használatával vesszük a fontot amit használni fogunk, a rajzolásra kész HDC-hez. Minden jövőbeni szöveggel kapcsolatos művelet ugyanezt a fontot fogja hasznélni, kivéve persze ha megváltoztatjuk.
Ezután beállítjuk a szöveg és háttérszínt. A háttérszín beállítása nem jelenti azt, hogy minden szöveghez látszódni is fog. Ez csak bizonyos műveleteknél lesz így. Ez függ az aktuális háttérszín módtól is (Background Mode). Ha ez OPAQUE (alapból ez van), akkor a rajzolt szöveg ki lesz töltve a háttérszínnel. Ha viszont ez a beállítás TRANSPARENT, akkor a szöveg háttérszín nélkül lesz megrajzolva, tehát ekkor a háttérszín opció hatástalan.
Most megrajzoljuk a szöveget a DrawText() használatával, átadjuk a használni kívánt HDC-t, és a sztringet. A harmadik paraméter a sztring hossza, de ez lehet -1, mert a DrawText() elég okos hozzá hogy tudja ezt magától is. A negyedik paraméter a prc, ez egy mutató az ügyfél RECT-re. A DrawText() ezen a téglalapon belül rajzol az általunk megadott további flag-ek alapján.
Első híváskor megadtunk egy DT_WORDBREAK paramétert, ez a bal felső sarokból indulva úgy igazítja a sortörést, hogy a téglalaphoz illeszkedjen. A második hívásnál sortörés nélkül nyomtatjuk a sort, függőlegesen és vízszintesen is középre igazítva.
Ügyfél újrarajzolás
Megjegyzés a példaprogramhoz: A WNDCLASS regisztrálásakor beállítottuk a CS_VREDRAW, és CS_HREDRAW osztály stílusokat. Ezzel azt kértük, hogy az ablak átméretezésekor mindent rajzoljon újra, ne csak a megváltozott dolgokat. Elég rondán nézne ki, ha átméretezéskor a szöveget nem tördelné újra.
Fontok váltása
Általában minden program ami lehetővé teszi a felhasználónak a font változtatását, felkínálja a betű méretének és színének a változtatását is. Ahogyan a fájlnév kiválasztását is megkönnyíti a Megnyitás/Mentés párbeszéd ablak, ugyanígy van font kiválasztó is. Ez bármily meglepő a ChooseFont() lesz, ami a CHOOSEFONT struktúrával működik. Az alapértelmezett beállításokat kínálja fel, és a felhasználó választásával tér vissza.
HFONT g_hfFont = GetStockObject(DEFAULT_GUI_FONT); COLORREF g_rgbText = RGB(0, 0, 0);void DoSelectFont(HWND hwnd) { CHOOSEFONT cf = {sizeof(CHOOSEFONT)}; LOGFONT lf; GetObject(g_hfFont, sizeof(LOGFONT), &lf); cf.Flags = CF_EFFECTS | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS; cf.hwndOwner = hwnd; cf.lpLogFont = &lf; cf.rgbColors = g_rgbText; if(ChooseFont(&cf)) { HFONT hf = CreateFontIndirect(&lf); if(hf) { g_hfFont = hf; } else { MessageBox(hwnd, "Font creation failed!", "Error", MB_OK | MB_ICONEXCLAMATION); } g_rgbText = cf.rgbColors; } }
Ebben a hívásban a hwnd egyszerűen a a hívó ablak handlere, ami a font kiválasztó párbeszéd ablakot hívja. A legegyszerűbb ha az aktuális HFONT LOGFONTstruktúráját kapja meg. Beállítjuk a LOGFONTstruktúra címére az lpLogFont mezőt, valamint a CF_INITTOLOGFONTSTRUCT flaget bekapcsoljuk. Így már tudja a ChooseFont(), hogy a meglévő beállításokkal induljon. A CF_EFFECTS jelzi, hogy a felhasználó szabadon választhat színt, valamint választhatja az aláhúzott, áthúzott opciókat is. Érdekes módon a félkövér és dőlt beállítások nem számítanak effektnek, az a betűtípus sajátja. Ha el akarjuk kerülni hogy ezeket kiválaszthassa, akkor figyelnünk kell a választását, és kézzel visszaírjuk az lfWeight és lfItalic mezőket.
A font színe nem a HFONT része, azt külön kell tárolnunk a CHOOSEFONT rgbColors mezőjében. Ez tárolja a színt a kiválasztás előtt, és után is. A CF_SCREENFONTS azt jelzi, hogy ezt a fontot képernyőre tervezték, szemben azokkal, amiket például nyomtatóra. Van aki mindkettőt támogatja, van aki csak az egyiket. A használható flag-ek listáját megtalálhatjuk az MSDN-en.
Szín választás
Annak érdekében hogy a felhasználó kiválaszthasson egy színt, rendelkezésünkre áll a ChooseColor() párbeszéd ablak. Ebben a példában a felhasználó kiválaszthatja a háttér színét.
COLORREF g_rgbBackground = RGB(255, 255, 255); COLORREF g_rgbCustom[16] = {0};void DoSelectColour(HWND hwnd) { CHOOSECOLOR cc = {sizeof(CHOOSECOLOR)}; cc.Flags = CC_RGBINIT | CC_FULLOPEN | CC_ANYCOLOR; cc.hwndOwner = hwnd; cc.rgbResult = g_rgbBackground; cc.lpCustColors = g_rgbCustom; if(ChooseColor(&cc)) { g_rgbBackground = cc.rgbResult; } }
Ez meglehetősen egyszerű. Megint a hwnd-t használjuk, ez jelzi a párbeszéd ablak szülőjét (a mi ablakunkat).
Todo: Valaki?
The CC_RGBINIT parameter says to start off with the colour we pass in through the rgbResult member, which is also where we get the colour the user selected when the dialog closes.
A g_rgbCustom 16 elemű (COLORREF típusú) tömb tárolja a felhasználó által kiválasztott színeket. Ezeket el lehet tárolni mondjuk a rendszerleíró adatbázisban, különben a program bezárásakor elvesznek. Ez a paraméter kötelező.
Vezérlő fontok
TODO:
Something else you might want to do at some point is change the font on the controls on your dialog or window. This is usually the case when using CreateWindow() to create controls as we've done in previous examples. Controls like windows use System by default, so we used WM_SETFONT to set a new font handle (from GetStockObject()) for the control to use. You can use this method with fonts you create from CreateFont() as well. Simply pass the font handle as wParam and set lParam to TRUE to make the control redraw.
I've done this in previous examples, but it makes sense to mention it here because it's relevant and very short:
SendDlgItemMessage(hwnd, IDC_OF_YOUR_CONTROL, WM_SETFONT, (WPARAM)hfFont, TRUE);Where hfFont is of course the HFONT you want to use, and IDC_OF_YOUR_CONTROL is the ID of whichever control you want to change the font of.
A bejegyzés trackback címe:
Kommentek:
A hozzászólások a vonatkozó jogszabályok értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a Felhasználási feltételekben és az adatvédelmi tájékoztatóban.