Kolejnym często spotykanym w wielu programach standardowym oknem systemu Windows jest okno wyboru czcionki, które w polskiej wersji językowej ma nazwę Czcionka. Do wywołania tego okna służy funkcja ChooseFont, która przyjmuje jako jedyny parametr wskaźnik do struktury typu CHOOSEFONT. Aby skorzystać z tej funkcji konieczne jest załączenie do projektu biblioteki:
#include <commdlg.h>
Wykorzystam funkcję w projekcie myNotepad by w praktyczny sposób pokazać, jak można w prosty sposób zwiększyć funkcjonalność tego programu.
Dodawanie modyfikacja menu programu myNotepad
Zanim zacznę modyfikację samego kodu programu warto dodać do menu głównego dodatkowe menu Ustawienia i w tej pozycji dodatkową pozycję Czcionka, identyfikator tej pozycji powinien być z automatu ustawiony na ID_USTAWIENIA_CZCIONKA, jeżeli tak nie jest to proszę to zmienić. Do zasobów można się dostać wciskając kombinację Ctrl+Shift+E lub wybierając z menu View->Resource View i pojawi się okno o nazwie Resource View, w którym na rozwijanej liście można znaleźć menu z projektu. Kliknięcie tej pozycji otworzy edytor graficzny tegoż menu, które po wprowadzeniu modyfikacji powinno wyglądać jak na poniższym rysunku.
Wprowadzenie poprawek do kodu programu myNotepad
Menu zostało zmodyfikowane, trzeba teraz na samym początku projektu załączyć wcześniej wspomniany plik commdlg.h. Teraz zaraz za bibliotekami załączonymi do projektu wstawić trzeba następującą funkcję odpowiedzialną za pozyskiwanie uchwytu czcionki:
#include <windows.h>
#include <commdlg.h>
#include <locale.h>
#include "resource.h"
#define ID_EDIT 3 // identyfikator kontrolki edit do przechowywania tekstu
HFONT GetChooseFont(HWND hWnd, LOGFONT *lf, COLORREF *c){
CHOOSEFONT cf;
ZeroMemory(&cf, sizeof(cf)); // zerowanie pól struktury
cf.lStructSize = sizeof(cf); // ustawienie pola określającego rozmiar struktury
cf.hwndOwner = hWnd; // uchwyt okna
cf.lpLogFont = lf; // wskaźnik do struktury LOGFONT
cf.Flags = CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS | CF_EFFECTS; // flagi: użyj wskaźnika do struktury lpLogFont do zainicjalizowania ustawień; wyświetlanie tylko czcionek wspieranych przez system; wyświetlaj dodatkowe opcje podkreślenia, przekreślenia i wyboru koloru czcionki
if(ChooseFont(&cf)){ // wywołanie okna
*c = cf.rgbColors; // pobieram kolor czcionki
return CreateFontIndirect(lf); // tworzę uchwyt i go zwracam
}
return NULL; // zwracam NULL gdy nie została wybrana żanda czcionka
}
Powyższy fragment kodu wstawiłem wraz z bibliotekami, które wcześniej zostały załączona aby wiadomo było, gdzie funkcję dodać do projektu. Jak widać, jeżeli funkcja ChooseFont zwróci TRUE to zwracam utworzony za pomocą funkcji CreateFontIndirect uchwyt do czcionki. Funkcja GetChooseFont przyjmuje trzy parametry, pierwszym jest oczywiście uchwyt okna rodzica, drugim jest wskaźnik na strukturę typu LOGFONT opisującą czcionkę natomiast trzeci to zmienna 24-bitowa typu COLORREF opisująca kolor w formacie rgb. Zmienna ta będzie używana do zmiany koloru czcionki rysowanej w kontrolce hedit.
Na sam początek w funkcji hwndProc dodać należy takie zmienna:
W powyższym wyrywku kodu opisane zostały komentarzem jedynie te elementy, które zostały dodane. Teraz w komunikacie WM_CREATE musi nastąpić znacząca zmiana:
lf = ncm.lfStatusFont; // tą linijkę trzeba dodać przed wywołaniem funkcji CreateFontIndirect
hf=CreateFontIndirect(&ncm.lfStatusFont); // tutaj było HFONT font = ....
c = RGB(0,0,0); // ustawienie koloru czcionki
SendMessage(hedit, WM_SETFONT, (WPARAM) hf, 0); // tutaj zamiast hf było wcześniej font
Dodać należy do funkcji hwndProc obsługę następującego komunikatu związanego z zmianą koloru czcionki w kontrolce hedit:
case WM_CTLCOLOREDIT: // komunikat umożliwiający zmianę kolorów w kontrolce
{
if(lParam == (LPARAM)hedit){ // jak lParam jest uchwytem okna hedit to
SetTextColor((HDC)wParam, c); // ustawiam kolor dla kontekstu urządzenia zawartego w wParam
}
return NULL; // zwracam null bo nie chcę zmieniać domyślnego koloru tła
}
W komunikacie WM_COMMAND w sekcji związanej z obsługą menu należy dodać kod związany z obsługą kliknięcia dodanej pozycji menu:
switch(LOWORD(wParam)){ // niższe słowo parametru wParam zawiera identyfikator klikniętej pozycji menu
case ID_USTAWIENIA_CZCIONKA: // opcja menu
{
HFONT nf = GetChooseFont(hWnd, &lf, &c); // wywołuję moją funkcję by wyświetlić okno i uzyskać nowy uchwyt czcionki
if(nf){ // jeżeli uchwyt nie jest NULL to
SendMessage(hedit, WM_SETFONT, (WPARAM) nf, 1); // ustawiam czcionkę kontrolki
DeleteObject(hf); // zwalniam uchwyt starej czcionki
hf = nf; // i zapamiętuję uchwyt nowej
}
}
break;
W komunikacie WM_DESTROY przed wywołaniem funkcji PostQuitMessage należy zwolnić uchwyt czcionki:
case WM_DESTROY:
{
DeleteObject(hf);
PostQuitMessage(0);
}
break;
Nowe funkcje i struktury
Lista nowo poznanych funkcji użytych w kodzie programu:
ChooseFont - wyświetla okno wyboru czcionki, funkcja ta jest ściśle powiązana z strukturami CHOOSEFONT oraz LOGFONT;
DeleteObject - funkcja zwalnia uchwyt czcionki;
Lista nowo poznanych struktur użytych w kodzie:
CHOOSEFONT - struktura zawierająca informacje niezbędne do wyświetlenia okna Czcionki za pomocą funkcji ChooseFont;