Font Chữ Trong Lập Trình C Trên Windows

FONT CHỮ TRONG LẬP TRÌNH C TRÊN WINDOWS

Trong Windows, khi trình bày văn bản, các ký tự được thể hiện theo nhiều dạng khác nhau. Đây là một trong những đặc trưng cơ bản của giao diện đồ họa - người dùng (GUI – Graphical User Interface). Để thực hiện điều này, Windows hỗ trợ nhiều dạng font chữ khác nhau. Trong phần này, chúng ta tìm hiểu các vấn đề chính về các font chữ, cũng như cách sử dụng chúng để trình bày văn bản.

Khái niệm font trong Windows

Một font chữ là một tập hợp các ký tự và ký hiệu cùng dạng, thể hiện qua kiểu chữ, loại chữ và kích cỡ chữ.
Kiểu chữ xác định các đặc trưng về ký tự và ký hiệu trong font chữ, ví dụ độ rộng, nét chữ dày hoặc mảnh, có chân (có gạch ngang hoặc các nét cong mảnh ở đầu các ký tự) hay không.
Loại chữ xác định độ đậm nhạt (trọng lượng) và độ nghiêng của dạng font thể hiện. Chia làm ba loại sau : roman, opaque, và italic. Font roman là dạng font chữ có trọng lượng trung bình, thường dùng trong in ấn. Font opaque là dạng được biến đổi ngiêng của font roman. Font italic là dạng font được thiết kế theo dạng nghiêng chuyên biệt.
Kích thước font chữ được tính như là khoảng cách từ chặn dưới của một ký tự có chân đến chặn trên của một ký tự hoa, và được tính theo đơn vị điểm (khoảng 0,013817 của 1 inch).
Một tập các font với một số kích cỡ và trọng lượng khác nhau nhưng cùng một kiểu loại được xem là một họ font chữ.
Các font chữ trong Windows được chia thành hai nhóm, gọi là font GDI và font thiết bị. Font GDI được lưu trữ dưới dạng tập tin trên đĩa, trong khi font thiết bị được thiết kế sẵn trong thiết bị xuất tương ứng, ví dụ máy in. Không như font GDI, khi in bằng font thiết bị, Windows không cần định dạng font, mà chỉ cần gởi nội dung dữ liệu trực tiếp đến thiết bị. Người dùng chọn trực tiếp font từ máy in để in. Đối với font GDI, Windows chuyển văn bản thành ảnh bitmap sau đó chuyển đến máy in để in. Như vậy, lợi điểm của font GDI là độc lập với thiết bị xuất, tuy nhiên tốc độ xử lý in chậm hơn.
Các font GDI thông thường gồm có : font bitmapfont vector và font TrueType. Font bitmap được cấu thành từ ma trận pixel, có lợi điểm là hiển thị nhanh, nhưng hạn chế trong việc thể hiện với các kích thước khác nhau (do chỉ phóng to – thu nhỏ, và khi phóng trông rất thô). Font vector thể hiện các ký tự như là tập hợp các nét vẽ (sử dụng các hàm GDI), do đó linh động và co giản hơn font bitmap, tuy nhiên được vẽ khá chậm và đường nét cũng không được mềm mại cho lắm.
Font TrueType là dạng font được sử dụng phổ biến nhất hiện nay, được lưu trữ dưới dạng một tập các điểm ảnh, kết hợp một số thuật toán biến đổi. Do đó thể hiện sắc xảo các đường nét trên màn hình và máy in. Chúng ta sẽ khảo sát các hàm xử lý cho các font chữ dạng này trong phần 5.3.3. Còn bây giờ chúng ta tìm hiểu cách sử dụng các font có sẵn của hệ thống.

Sử dụng font định nghĩa sẵn

Khi ta gọi các hàm vẽ chữ TextOutTabbedTextOutExtTextOut hoặc DrawText, Windows sẽ sử dụng font chữ đang được chọn trong DC để hiện thị nội dung văn bản. Ta có thể dùng một số font được Windows định nghĩa sẵn, thường gọi là font hệ thống (phân biệt các font do người dùng tạo trong quá trình xử lý văn bản – xem phần 5.3.3). Tên macro của các font này thể hiện trong bảng sau :
Macro các font định nghĩa sẵn.
MACROFONT
ANSI_FIXED_FONTFont với kích thước cố định của ký tự dựa trên Windows. Font Courier là một ví dụ điển hình của dạng font này.
ANSI_VAR_FONTFont với độ rộng ký tự thay đổi dựa trên các ký tự chuẩn của Windows. Font MS San Serif là một ví dụ điển hình.
DEVICE_DEFAULT_FONTFont với thiết bị đã cho được chọn mặc nhiên. Dạng font này thường co sẵn trong hệ thống để điều khiển việc trình bày trên thiết bị. Tuy nhiên, đối với một số thiết bị, font được cài đặt ngay trên thiết bị. Ví dụ, đối với máy in, các font thiết bị cài sẵn thực hiện thao tác in nhanh hơn so với việc load bitmap ảnh về từ máy tính.
DEFAULT_GUI_FONTFont của giao diện đồ họa được thiết lập mặc định.
OEM_FIXED_FONTFont chữ cố định, dựa trên bộ ký tự OEM. Ví dụ, đối với máy IBM®, font OEM dựa trên bộ ký tự IBM PC.
SYSTEM_FONTFont hệ thống của Windows. Được hệ điều hành dùng để trình bày các thành phần giao diện như thanh tiêu đề, menu, nội dung văn bản trong các hộp thoại thông điệp. Các font hệ thống này luôn có sẵn khi cài hệ điều hành, trong khi các font khác cần phải cài thêm tùy theo ứng dụng sau này.
SYSTEM_FIXED_FONTFont Windows được sử dụng như font hệ thống trong các phiên bản trước 3.0.
Việc chọn và sử dụng font hệ thống trong Windows khá đơn giản. Để làm điều này, đầu tiên chương trình tạo ra handle của font - kiểu biến HFONT, sau đó chọn font dùng hàm GetStockObject.
HGDIOBJ GetStockObject(int fnObject);
Trong đó, kiểu HGDIOBJ là HFONT, biến fnObject là một trong các macro ở bảng trên. Nếu thành công, hàm này trả về handle của font hệ thống hiện hành. Ngược lại, giá trị trả về là NULL. Để thay đổi font, ta gọi hàm SelectObject.
HGDIOBJ SelectObject(HDC hDC, HGDIOBJ hGDIObj);
Hoặc gọn hơn, ta có thể gọi :
SelectObject(hDC.GetStockObject(fnObject));
Khi đó, font hiện hành trong DC là font vừa được gọi. Hàm trả về macro font trước đó. Nếu không thành công, lỗi trả về là GDI_ERROR. Thường khi gọi font định sẵn, nếu các font không có sẵn, hệ thống sẽ trả về font hệ thống (SYSTEM_FONT). Lưu ý, chỉ nên dùng các font có sẵn nếu chế độ hiện thị của DC ứng dụng hiện thời là MM_TEXT.
Để xem các thuộc tính của font hệ thống, ví dụ kích thước của bộ font để tính toán vị trí khi xuất văn bản, ta dùng hàmGetTextMetrics.
BOOL GetTextMetrics(HDC hDC, LPTEXTMETRIC lpTM);
Biến lpTM là con trỏ đến cấu trúc TEXTMETRIC mà nếu hàm thực hiện thành công (trả về giá trị nonzero) sẽ chứa các tham số của font.
Đoạn chương trình sau minh họa việc chọn font định sẵn vào một DC, sau đó viết một chuỗi ký tự sử dụng font này.
HFONT hfnt, hOldFont;
hfnt = GetStockObject(ANSI_VAR_FONT);
if (hOldFont = SelectObject(hdc, hfnt))
{
TextOut(hdc, 10, 50, "Sample ANSI_VAR_FONT text.", 26);
SelectObject(hdc, hOldFont);
}
Tuy nhiên, font chữ hệ thống khá nghèo nàn, không đáp ứng đủ nhu cầu trình bày văn bản. Vì thế, Windows hỗ trợ các hàm sử dụng các font chữ tự tạo. Phần tiếp theo sẽ bàn kỹ hơn về các hàm xử lý các font này.

Sử dụng font tự tạo

Font logic là một đối tượng GDI có handle kiểu HFONT. Một font logic là một mô tả của một font chữ thực tế. Tương tự như viết vẽ logic và chổi sơn logic, font logic là một đối tượng trừu tượng, và trở thành font thực tế trong DC khi ứng dụng gọi hàm SelectObject.
Đầu tiên, ta cần định nghĩa các trường trong cấu trúc LOGFONT theo một trong hai cách sau :
  • Thiết lập các trường trong cấu trúc LOGFONT dựa trên các đặc tính của font bạn quan tâm. Trong trường hợp này, khi gọi hàm SelectObject, Windows sẽ sử dụng một thuật toán "ánh xạ font" để chọn một font tương thích nhất hiện có trên thiết bị.
  • Chọn font trong hộp thoại Font, hàm ChooseFont sẽ khởi gán các giá trị trong cấu trúc LOGFONT theo thuộc tính font được chọn.
Để sử dụng font này trong các thao tác xuất văn bản, trước hết ứng dụng cần khởi tạo font logic, rồi chuyển cho DC. Việc tạo font logic được thực hiện bằng cách gọi hàm CreateFont hoặc hàm CreateFontIndirect. Tuy nhiên, hàm CreateFont ít được sử dụng hơn do hàm cần gởi các biến trong cấu trúc LOGFONT, trong khi hàm CreateFontIndirect chỉ cần biến con trỏ LOGFONT. Cả hai hàm đều trả về handle của font logic HFONT.
Trước khi ứng dụng có thể xuất văn bản, font logic cần được ánh xạ tương ứng với một font vật lý trong thiết bị xuất, hoặc font nạp vào hệ điều hành. Tiến trình này được thực hiện khi ứng dụng gọi hàm SelectObject. Khi đó, ta có thể dùng hàm GetTextMetrics(hoặc các hàm tương đương) xác định kích thước và đặc trưng của font thực để tính vị trí và xuất văn bản ra thiết bị xuất.
Sau khi dùng font, ta cần loại bỏ font dùng hàm DeleteObject. Chú ý không được xoá font trong DC đang thực thi, hoặc font hệ thống.

Cấu trúc LOGFONT và TEXTMETRIC

Để tạo font logic, ta có thể gọi hàm CreateFont và CreateFontIndirect. Hàm CreateFontIndirect nhận con trỏ cấu trúc LOGFONT. Hàm CreateFont có biến là 14 trường của LOGFONT. Xét định nghĩa của cấu trúc LOGFONT :
typedef struct tagLOGFONT // lf
{
LONG lfHeight;
LONG lfWidth;
LONG lfEscapement;
LONG lfOrientation;
LONG lfWeight;
BYTE lfItalic;
BYTE lfUnderline;
BYTE lfStrikeOut;
BYTE lfCharSet;
BYTE lfOutPrecision;
BYTE lfClipPrecision;
BYTE lfQuality;
BYTE lfPitchAndFamily;
TCHAR lfFaceName[LF_FACESIZE];
} LOGFONT;
Hai trường đầu trong cấu trúc LOGFONT tính theo đơn vị logic, do đó phụ thuộc vào chế độ hiển thị. Trường lfHeight là chiều cao của ký tự, nhận giá trị mặc định của font nếu bằng 0. Nếu lfHeight âm, Windows xác định kích cỡ font qua giá trị tuyệt đối gần nhất. Giá trị dương của lfHeight xấp xỉ bằng giá trị tmHeight tương ứng trong cấu trúc TEXTMETRICS. Trường lfWidth xác định độ rộng ký tự. Trong trường hợp lfWidth bằng 0, Windows sẽ chọn font tương ứng dựa vào chiều cao lfHeight. Giá trị lfWidth khác 0 thường được sử dụng cho các font TrueType (không tương thích cho các font vector). Trường này tương đương trường tmAveCharWidth trong cấu trúc TEXTMETRICS.
Hai trường tiếp theo xác định hướng hiển thị của các ký tự trong chuỗi. Trường lfEscapement xác định góc lệch giữa đường cơ sở (base line) và trục của thiết bị. Giá trị nhập vào là một bội số của 10. Chuỗi xuất theo hướng mặc định (trái sang phải), hướng lên, từ phải sang trái, và hướng xuống nếu giá trị lần lượt là 0, 900, 1800, và 2700. Trường lfOrientation xác định hướng đường cơ sở của từng ký tự so với trục x. Giá trị được xác định tương tự lfEscapement. Nếu ứng dụng gọi hàm trong Windows NT, với chế độ đồ họa là GM_ADVANCED, giá trị lfEscapement được xác định độc lập với lfOrientation. Trong các trường hợp khác, hai giá trị này phải được thiết lập như nhau.
Ví dụ sau thể hiện việc xuất một chuỗi quanh tâm vùng làm việc của cửa sổ ứng dụng bằng cách thay đổi giá trị của trường lfEscapement và lfOrientation từng 10 độ.
RECT rc;
int angle;
HFONT hfnt, hfntPrev;
LPSTR lpszRotate = "String to be rotated.";
// Cấp phát vùng nhớ cho cấu trúc LOGFONT.
PLOGFONT plf=(PLOGFONT)LocalAlloc(LPTRsizeof(LOGFONT));
// Xác định tên và độ đậm nhạt của font.
lstrcpy(plf->lfFaceName, "Arial");
plf->lfWeight = FW_NORMAL;
// Thu nhận kích thước của vùng làm việc cửa sổ ứng dụng .
GetClientRect(hwnd, &rc);
// Thiết lập chế độ nền TRANSPARENT cho thao tác xuất văn bản.
SetBkMode(hdc, TRANSPARENT);
// Vẽ chuỗi quay quanh tâm vùng làm việc từng 10 độ (36 lần).
for (angle = 0; angle < 3600; angle += 100)
{
plf->lfEscapement = angle;
hfnt = CreateFontIndirect(plf);
hfntPrev = SelectObject(hdc, hfnt);
TextOut(hdc, rc.right/2, rc.bottom/2, lpszRotate, lstrlen(lpszRotate));
SelectObject(hdc, hfntPrev);
DeleteObject(hfnt);
}
// Chuyển chế độ hiển thị về lại dạng OPAQUE.
SetBkMode(hdc, OPAQUE);
// Giải phóng vùng nhớ đã cấp phát cho cấu trúc LOGFONT.
LocalFree((LOCALHANDLE) plf);
Trường tiếp theo là lfWeight xác định độ độ đậm nhạt của ký tự, có giá trị từ 0 đến 1000. Trong trường hợp bằng 0, Windows sử dụng giá trị mặc định. Để tiện dùng, ta dùng một số macro sau :
Macro xác định độ đậm nhạt lfWeight.
TênGiá trị
FW_DONTCARE0
FW_THIN100
FW_EXTRALIGHT200
FW_ULTRALIGHT200
FW_LIGHT300
FW_NORMAL400
FW_REGULAR400
FW_MEDIUM500
FW_SEMIBOLD600
FW_DEMIBOLD600
FW_BOLD700
FW_EXTRABOLD800
FW_ULTRABOLD800
FW_HEAVY900
FW_BLACK900
Các trường lfItalic, lfUnderline, lfStrikeOut xác định font nghiêng, có gạch dưới, gạch ngang nếu được thiết lập bằng TRUE.
Trường lfCharSet xác định tập ký tự sử dụng. Giá trị OEM_CHARSET xác định tập ký tự phụ thuộc hệ điều hành. Thông thường, ta sử dụng DAFAULT_CHARSET (tập ký tự mặc định). Việc chọn tập ký tự là rất quan trọng, nếu ứng dụng sử dụng font có tập ký tự không xác định, hệ thống không thể thông dịch chúng.
Các trường còn lại khá phức tạp. Chúng ta không phân tích các giá trị của chúng ở đây. Trường lfOutPrecision định nghĩa độ chính xác (có thể có) của font thực tế so với font yêu cầu. Trường lfClipPrecision xác định cách thức các ký tự bị cắt bỏ khi nằm ngoài vùng clipping. Trường lfQuality dùng cho font vector, xác định cách thức GDI định nghĩa độ chính xác của font logic so với font vật lý. Trường lfPitchAndFamily xác định họ font chữ. Trường lfFaceName xác định tên kiểu font.
Sau khi đã chọn font cho DC, ta cần biết các đặc trưng của font hiện tại dùng cho việc xuất văn bản bằng hàm GetTextMetrics. Ta có cấu trúc TEXTMETRIC :
typedef struct tagTEXTMETRIC // tm
{
LONG tmHeight;
LONG tmAscent;
LONG tmDescent;
LONG tmInternalLeading;
LONG tmExternalLeading;
LONG tmAveCharWidth;
LONG tmMaxCharWidth;
LONG tmWeight;
LONG tmOverhang;
LONG tmDigitizedAspectX;
LONG tmDigitizedAspectY;
BCHAR tmFirstChar;
BCHAR tmLastChar;
BCHAR tmDefaultChar;
BCHAR tmBreakChar;
BYTE tmItalic;
BYTE tmUnderlined;
BYTE tmStruckOut;
BYTE tmPitchAndFamily;
BYTE tmCharSet;
} TEXTMETRIC;
Các trường về kích thước được tính theo đơn vị logic, phụ thuộc vào chế độ hiển thị. Trường tmHeight cho biết chiều cao của ký tự, bằng tổng hai trường tmAscent (phần trên đường cơ sở) và tmDescent (phần dưới đường cơ sở). Trường tmInternalLeading xác định khoảng cách bên trong đường biên xác định bởi tmHeight. Người thiết kế có thể cho giá trị này bằng 0. Trường tmExternalLeading là khoảng cách Windows thêm vào giữa các dòng. Người dùng cũng có thể gán giá trị này bằng 0. Trường tmAveCharWidth cho biết độ rộng trung bình của các ký tự chữ thường. Trường tmMaxCharWidth cho biết độ rộng ký tự lớn nhất tính theo đơn vị logic. Đối với bộ font fixed-pitch (độ rộng không đổi), giá trị này bằng tmAveCharWidth.
Trường tmOverhang cho biết phần mở rộng (theo đơn vị logic) mà Windows thêm vào font vector khi font nghiêng hoặc tô đậm. Khi font nghiêng, giá trị tmAveCharWidth không thay đổi, bởi vì chuỗi các ký tự nghiêng vẫn có độ rộng bằng chuỗi chữ thông thường. Trong trường hợp chữ đậm, Windows sẽ mở rộng từng ký tự. Khi đó, tmAveCharWidth của ký tự bình thường bằng tmAveCharWidth trừ đi độ lớn tmOverhang của ký tự đậm.
Trường tmDigitizedAspectX và tmDigitizedAspectY xác định tỉ lệ co của font. Chúng ta cũng có thể xác định chúng bằng hàmGetDeviceCaps (xác định các thông tin thiết bị) với các thông số của nIndex là LOGPIXELSX và LOGPIXELSY.
int GetDeviceCaps(HDC hDC, int nIndex);
Trường tmFirstChar xác định giá trị ký tự đầu tiên trong font, tmLastChar xác định giá trị ký tự cuối cùng. Nếu gọi hàmGetTextMetricsW, giá trị này sẽ lớn hơn 255. Trường tmDefaultChar chứa giá trị Windows dùng để hiển thị các ký tự không tồn tại trong bộ font, thường là hình chữ nhật. Trường tmBreakChar được dùng để ngắt từ khi canh chỉnh văn bản. Nếu không dùng các font đặc biệt, ví dụ font EBCDIC, giá trị này chính là giá trị ký tự khoảng trắng (mã bằng 32).
Các trường tmWeight, tmItalic, tmUnderlined, tmStruckOut, tmCharSet và tmPitchAndFamily giống các trường lfWeight, lfItalic, lfUnderline, lfStrikeOut, lfCharSet và lfPitchAndFamily trong cấu trúc LOGFONT.

Sử dụng hộp thoại chọn font

Để chọn font, ta có thể sử dụng hộp thoại font. Đầu tiên, ứng dụng khởi tạo các giá trị trong cấu trúc CHOOSEFONT, sau đó gọi hàmChooseFont để hiển thị hộp thoại liệt kê danh sách các font. Sau khi người dùng chọn một font có sẵn và chọn OK, hàmChooseFont sẽ khởi gán các giá trị tương ứng vào cấu trúc LOGFONT. Ứng dụng có thể gọi hàm CreateFontIndirect để tạo một font logic dựa trên các yêu cầu của người dùng.
Xét cấu trúc CHOOSEFONT.
typedef struct tagCHOOSEFONT // cf
{
DWORD lStructSize;
HWND hwndOwner;
HDC hDC;
LPLOGFONT lpLogFont;
INT iPointSize;
DWORD Flags;
DWORD rgbColors;
LPARAM lCustData;
LPCFHOOKPROC lpfnHook;
LPCTSTR lpTemplateName;
HINSTANCE hInstance;
LPTSTR lpszStyle;
WORD nFontType;
WORD ___MISSING_ALIGNMENT__;
INT nSizeMin;
INT nSizeMax;
} CHOOSEFONT;
Trường lStructureSize xác định số byte kích thước cấu trúc. Trường hwndOwner xác định cửa sổ chứa hộp thoại chọn font. Trường này có thể là một handle cửa sổ xác định, hoặc cũng có thể bằng NULL nếu hộp thoại không xác định cửa sổ cha. Trường hDC là DC của máy in có các font được liệt kê trong hộp thoại. Chỉ dùng trường hDC nếu thiết lập trường Flags với cờ CF_PRINTERFONTS hoặc CF_BOTH; trong các trường hợp khác, giá trị trường này bị bỏ qua.
Trường lpLogFont trỏ đến cấu trúc LOGFONT. Nếu ta thiết lập trong trường Flags giá trị CF_INITTOLOGFONTSTRUCT, và khởi gán các giá trị cho nó, hàm ChooseFont sẽ khởi tạo hộp thoại với font gần giống nhất. Sau khi ta chọn OK đóng hộp thoại, hàmChooseFont sẽ thiết lập các giá trị của cấu trúc này dựa trên các chọn lựa tương ứng.
Trường iPointSize xác định kích thước font được chọn theo đơn vị 1/10 điểm. Giá trị này sẽ được thiết lập sau khi ta đóng hộp thoại.
Trường Flags là tập các bit cờ được dùng để khởi tạo hộp thoại Font. Trường này có thể kết hợp các giá trị sau :
Các macro cờ Flags khởi tạo hộp thoại Font.
CF_APPLYHộp thoại có thêm button Apply. Ta phải cung cấp hàm hook xử lý thông điệp WM_COMMAND cho button này.
CF_BOTHHộp thoại liệt kê danh sách các font máy in và font màn hình. Trường hDC sẽ xác định DC liên quan đến máy in. Cờ này cần kết hợp với cờ CF_SCREENFONTS và CF_PRINTERFONTS.
CF_TTONLYXác định hàm ChooseFont chỉ quản lý và chọn lựa trên font dạng TrueType.
CF_EFFECTĐể hộp thoại thể hiện các control cho phép người dùng thiết lập chữ gạch ngang, gạch dưới và chọn màu. Nếu cờ này được thiết lập, ta có thể sử dụng trường rgbColors xác định màu font ban đầu. Ta cũng có thể sử dụng trường lfStrikeOut và lfUnderline của cấu trúc LOGFONT trỏ đến trường lpLogFont xác định các thiết lập ban đầu của checkbox gạch ngang và gạch dưới ký tự. Hàm ChooseFont sẽ sử dụng các trường này để trả về giá trị chọn lựa của người dùng.
CF_ENABLEHOOKCho phép thủ tục hook thiết lập trong trường lpfnHook.
CF_ENABLETEMPLATEChỉ ra trường hInstance và lpTemplateName xác định hộp thoại mẫu sử dụng mặc định.
CF_ENABLETEMPLATEHANDLEChỉ ra trường hInstance xác định khối dữ liệu chứa hộp hoại mẫu trước khi nạp. Hệ thống sẽ bỏ qua giá trị của trường lpTemplateName.
CF_FORCEFONTEXISTXác định hàm ChooseFont sẽ chỉ ra lỗi nếu người dùng cố chọn font hoặc kiểu không tồn tại.
CF_INITTOLOGFONTSTRUCTXác định hàm ChooseFont phải sử dụng cấu trúc LOGFONT qua trường lpLogFont để khởi tạo hộp thoại.
CF_LIMITSIZEXác định hàm ChooseFont chỉ chọn font có kích thước trong giới hạn từ nSizeMin đến nSizeMax.
CF_NOOEMFONTSGiống cờ CF_NOVECTORFONTS.
CF_NOFACESELKhi sử dụng cấu trúc LOGFONT để khởi tạo các control của hộp thoại, trong đó combo box tên font không thể hiện một font nào đang được chọn cả.
CF_NOSCRIPTSELKhông cho phép chọn combo box Scrip. Khi cờ này được thiết lập, trường lfCharSet của cấu trúc LOGFONT được thiết lập với giá trị DEFAULT_CHARSET khi hàm ChooseFont trả về. Cờ này chỉ dùng khi khởi tạo hộp thoại.
CF_NOSTYLESELKhi sử dụng cấu trúc LOGFONT để khởi tạo các control của hộp thoại, ta không dùng kiểu font nào cả (combo box style).
CF_NOSIZESELKhi sử dụng cấu trúc LOGFONT để khởi tạo các control của hộp thoại, ta không hiển thị chọn lựa ban đầu cho combo box kích thước.
CF_NOVECTORFONTSHàm ChooseFont không cho phép chọn lựa font vector.
CF_NOVERTFONTSHộp thoại font chỉ liệt kê các font viết hướng ngang.
CF_PRINTERFONTSHộp thoại chỉ liệt kê các font hỗ trợ máy in liên quan đến DC xác định qua handle hDC.
CF_SCALABLEONLYChỉ định hàm ChooseFont chỉ cho phép chọn lựa các font có thể co giãn (font vector, TrueType, …).
CF_SCREENFONTSHộp thoại chỉ liệt kê các font màn hình được hệ thống hỗ trợ.
CF_SHOWHELPHộp thoại sẽ hiển thị nút Help. Trường hwndOwner phải xác định window nhận thông điệp HELPMSGSTRINGmà hộp thoại đưa ra khi người dùng nhấn button Help.
CF_USESTYLEXác định trường lpszStyle trỏ đến vùng đệm chứa dữ liệu kiệu mà hàm ChooseFont dùng để khởi tạo combo box Font Style. Sau khi người dùng đóng hộp thoại, hàm ChooseFont chép dữ liệu kiểu vào vùng đệm.
CF_WYSIWYGXác định hàm ChooseFont cho phép chọn lựa các font có sẵn cho máy in và màn hình. Nếu cờ này được thiết lập, cả cờ CF_BOTH và CF_SCALABLEONLY cũng cần được thiết lập.
Nếu cờ CF_EFFECT được thiết lập, trường rgbColors sẽ xác định màu chữ khởi tạo. Nếu hàm ChooseFont thực hiện thành công, trường này sẽ chứa giá trị RGB của màu chữ mà người dùng đã chọn.
Trường lCustData xác định dữ liệu được ứng dụng định nghĩa chuyển cho hàm hook gán bởi giá trị lpfnHook. Nếu hệ thống gởi thông điệp WM_INITDIALOG, giá trị lParam của thông điệp là con trỏ trỏ đến cấu trúc CHOOSEFONT xác định khi hộp thoại được tạo.
Trường lpfnHook trỏ đến thủ tục hook CFHookProc xử lý các thông điệp của hộp thoại. Để sử dụng giá trị này, cần phải thiết lập cờ với CF_ENABLEHOOK.
Trường lpTemplateName trỏ đến chuỗi (kết thúc bằng ký tự NULL) xác định tên tài nguyên hộp thoại mẫu, liên quan với trường hInstance. Nếu thiết lập cờ CF_ENABLETEMPLATEHANDLE, hInstance là handle của đối tượng vùng nhớ chứa hộp thoại mẫu. Nếu thiết lập cờ CF_ENABLETEMPLATE, hInstance xác định module chứa hộp thoại mẫu có tên ở trường lpTemplateName.
Trường lpszStyle trỏ đến vùng đệm chứa dữ liệu kiểu. Nếu thiết lập cờ CF_USESTYLE, hàm ChooseFont sẽ sử dụng dữ liệu trong vùng đệm để khởi tạo combo box kiểu font. Khi người dùng đóng hộp thoại, hàm ChooseFont chép chuỗi trong combo box kiểu font vào vùng đệm này.
Trường nFontType xác định dạng font trả về. Có thể kết hợp các giá trị sau :
Các macro xác định dạng font trả về.
BOLD_FONTTYPEFont chữ đậm. Giá trị này được lặp lại trong trường lfWeight của cấu trúc LOGFONT, và bằng FW_BOLD.
ITALIC_FONTTYPEFont chữ nghiêng. Giá trị này được lặp lại trong trường lfItalic của cấu trúc LOGFONT.
PRINTER_FONTTYPEFont chữ là font máy in.
REGULAR_FONTTYPEFont chữ bình thường. Giá trị này được lặp lại trong trường lfWeight của cấu trúc LOGFONT, và bằng FW_REGULAR .
SCREEN_FONTTYPEFont chữ là font màn hình.
SIMULATED_FONTTYPEFont dựa theo giao diện GUI.
Trường nSizeMin và nSizeMax xác định kích cỡ chữ nhỏ nhất và lớn nhất mà người dùng có thể chọn. Hàm ChooseFont chỉ nhận ra các giá trị này khi cờ CF_LIMITSIZE được thiết lập.
Như đã trình bày ở trên, để tạo hộp thoại font cho phép người dùng chọn các thuộc tính của một font logic, ta dùng hàmChooseFont.
BOOL ChooseFont(LPCHOOSEFONT lpcf);
Với lpcf trỏ đến cấu trúc CHOOSEFONT chứa các thông tin dùng để khởi tạo hộp thoại. Khi hàm trả về, cấu trúc này chứa các thông tin mà người dùng chọn.
Nếu người dùng nhấn nút OK trên hộp thoại, hàm trả về giá trị khác 0. Ngược lại, nếu chọn Cancel hoặc đóng (close) hộp thoại, giá trị trả về bằng 0.
Ví dụ sau minh họa việc chọn font logic sử dụng hộp thoại font.
HFONT FAR PASCAL MyCreateFontvoid )
{
CHOOSEFONT cf;
LOGFONT lf;
HFONT hfont;
// Khởi tạo các trường trong cấu trúc CHOOSEFONT.
cf.lStructSize = sizeof(CHOOSEFONT);
cf.hwndOwner = (HWND)NULL;
cf.hDC = (HDC)NULL;
cf.lpLogFont = &lf;
cf.iPointSize = 0;
cf.Flags = CF_SCREENFONTS;
cf.rgbColors = RGB(0,0,0);
cf.lCustData = 0L;
cf.lpfnHook = (LPCFHOOKPROC)NULL;
cf.lpTemplateName = (LPSTR)NULL;
cf.hInstance = (HINSTANCE) NULL;
cf.lpszStyle = (LPSTR)NULL;
cf.nFontType = SCREEN_FONTTYPE;
cf.nSizeMin = 0;
cf.nSizeMax = 0;
// Hiển thị hộp thoại font.
ChooseFont(&cf);
/* Tạo font logic dựa trên các chọn lựa của người dùng và trả về handle của font logic */
hfont = CreateFontIndirect(cf.lpLogFont);
return (hfont);
}

Ví dụ về hiển thị văn bản bằng các font khác nhau

Sau khi tìm hiểu về việc xuất nội dung văn bản và sử dụng font chữ bằng các hàm Win32® API, ta có thể trình bày văn bản một cách linh động hơn. Phần này đưa ra ví dụ xuất một chuỗi văn bản theo các font khác nhau trên cùng một dòng.
Một trong các cách trình bày một dòng văn bản với nhiều font chữ khác nhau là sử dụng hàm GetTextExtentPoint32 sau mỗi lần gọi hàm TextOut và cộng chiều dài nhận được vào vị trí hiển thị hiện tại. Ví dụ sau xuất câu "This is a sample string", sử dụng chữ đậm để viết "This is a", chữ nghiêng để viết "sample", và trở lại chữ đậm để viết “string.". Sau khi xuất xong, chương trình phục hồi lại dạng font mặc định.
int XIncrement;
int YStart;
TEXTMETRIC tm;
HFONT hfntDefault, hfntItalic, hfntBold;
SIZE sz;
LPSTR lpszString1 = "This is a ";
LPSTR lpszString2 = "sample ";
LPSTR lpszString3 = "string.";
/* Tạo font chữ đậm và nghiêng (hàm này không viết ở đây) */
hfntItalic = MyCreateFont();
hfntBold = MyCreateFont();
/* Chọn font chữ đậm và viết chuỗi tại vị trí xác định bởi cặp tham số (XIncrement, YStart) */
XIncrement = 10;
YStart = 50;
hfntDefault = SelectObject(hdc, hfntBold);
TextOut(hdc, XIncrement, YStart, lpszString1, lstrlen(lpszString1));
/* Tính độ dài của chuỗi đầu tiên và cộng giá trị này vào giá trị XIncrement để thực hiện thao tác xuất chuỗi tiếp theo */
GetTextExtentPoint32(hdc, lpszString1, lstrlen(lpszString1), &sz);
XIncrement += sz.cx;
/* Xác định độ lớn phần mở rộng ký tự qua cấu trúc TEXTMETRIC và trừ bớt XIncrement. (Điều này chỉ cần thiết cho font vector) */
GetTextMetrics(hdc, &tm);
XIncrement -= tm.tmOverhang;
/* Chọn font nghiêng và viết chuỗi thứ hai bắt đầu tại vị trí (XIncrement, YStart) */
hfntBold = SelectObject(hdc, hfntItalic);
GetTextMetrics(hdc, &tm);
XIncrement -= tm.tmOverhang;
TextOut(hdc, XIncrement, YStart, lpszString2, lstrlen(lpszString2));
/* Tính độ dài của chuỗi đầu tiên và cộng giá trị này vào giá trị XIncrement để thực hiện thao tác xuất chuỗi tiếp theo */
GetTextExtentPoint32(hdc, lpszString2, lstrlen(lpszString2), &sz);
XIncrement += sz.cx;
/* Chọn lại font chữ đậm và viết chuỗi thứ ba bắt đầu tại vị trí (XIncrement, YStart) */
SelectObject(hdc, hfntBold);
TextOut(hdc, XIncrement-tm.tmOverhang, YStart, lpszString3, lstrlen(lpszString3));
/* Chọn lại font ban đầu */
SelectObject(hdc, hfntDefault);
/* Xoá các đối tượng font chữ */
DeleteObject(hfntItalic);
DeleteObject(hfntBold);
Trong ví dụ trên, ta sử dụng hàm GetTextExtentPoint32 để nhận chiều dài và chiều cao của chuỗi văn bản.
BOOL GetTextExtentPoint32(HDC hDC, LPCTSTR lpString, int cbString, LPSIZE lpSize);
Trong đó hDC là handle của DC, lpString trỏ đến chuỗi văn bản có chiều dài xác định bởi cbString. Và lpSize trỏ đến cấu trúc SIZEchứa kích thước của chuỗi ký tự cần xác định.
typedef struct tagSIZE
{
LONG cx;
LONG cy;
} SIZE;
Cấu trúc trên xác định chiều rộng và chiều cao của một hình chữ nhật lần lượt qua hai biến cx và cy.
Nếu thực hiện thành công, hàm trả về giá trị khác 0. Ngược lại, giá trị trả về bằng 0.

0 Comment:

Đăng nhận xét

Thank you for your comments!