Tải bản đầy đủ (.pdf) (8 trang)

Tài liệu Xuất chữ ra vùng client của ứng dụng pptx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (251.84 KB, 8 trang )

Iczelion’s Tutorial Win32 ASM Tutorial 4 : Painting with Text
Xuất chữ ra vùng client của ứng dụng

Một trong các đặc tính nổi bật nhất của Windows là giao diện giao tiếp với người
dùng. Nhờ đặc tính này, nhiều dạng dữ liệu thông tin khác nhau được máy tính hỗ trợ khi
xuất ra màn hình, máy in, … Trong đó xuất văn bản ra vùng làm việc của các ứng dụng
Win32 là hình thức phổ biến nhất trong giao diện đồ họa.

Ở các bài viết trước, các thao tác xuất thông tin chỉ được thực hiện thông qua các
cửa sổ thông báo, hộp thoại và các phần tử điều khiển. Chương nà
y sẽ trình bày cách thể
hiện nội dung văn bản trên vùng làm việc của cửa sổ thông qua các hàm Win32 API.

Trong bài viết này, chúng ta học cách làm thế nào để xuất chữ ra vùng client của
ứng dụng, tìm hiểu sâu hơn về việc xử lý thông điệp WM_PAINT, các khái niệm về thiết
bị ngữ cảnh (device context) và các thông tin metrics.

Tìm hiểu về Device Context

Văn bản là
một trong những đối tượng đồ họa của hệ thống. Mỗi ký tự là tập hợp
của nhiều điểm ảnh (pixels) được xếp thành những mẫu riêng biệt. Đó là lý do tại sao
người ta dùng thuật ngữ là vẽ painting chứ không phải là writing. Thông thường, bạn
“vẽ” chữ trong vùng client của ứng dụng (thực tế, bạn cũng có thể vẽ bê
n ngoài vùng
client, nhưng đó là vấn đề khác). Việc xuất chữ ra màn hình trong Windows hoàn toàn
khác trong Dos. Trong Dos, ở chế độ văn bản màn hình có kích thước 80 x 25 (80 cột x
25 dòng) và chỉ sử dụng bởi một ứng dụng. Nhưng trong Windows thì khác, màn hình
được chia sẽ cho những ứng khác nhau. Một vài bắt buộc phải tuân thủ để tránh tình trạng
màn hình của ứng dụng này chồng lên màn hình của ứng dụng khác .Vì thế, HĐH sẽ giới
hạn vùng painting của mỗi cửa sổ là vùng client của chính nó.



Vùng client của cửa sổ là phần của cửa sổ ứng dụng trừ thanh tiêu đề (title), đường viền (border), thanh
menu (menu bar), thanh công cụ (tool bar), thanh trạng thái (status bar) và thanh cuộn (scrollbar). Hình
ảnh của vùng client được thể hiện như sau:




Người dịch: Benina (REA TEAM) Trang 1
Tổng hợp và hiệu chỉnh: NhatPhuongLe (VNCERT TEAM)
Iczelion’s Tutorial Win32 ASM Tutorial 4 : Painting with Text
Kích thước vùng client của cửa sổ window không là hằng số. Người dùng có thể thay đổi
kích thước này bất kỳ khi nào họ muốn. Vì vậy, bạn cần phải xác định kích thước của
vùng client một cách linh động.


Khi một chương trình cần vẽ lên trên vùng client, bạn phải “xin phép”, xem HĐH có chấp
thuận cho bạn có quyền lên vùng client của ứng dụng hay không. HĐH sẽ xác định kích
thước của vùng client của ứng dụng, font chữ, màu chữ và các thuộc tính khác của giao
diện thiết bị đồ họa (GDI – Graphics Device Interface), và gởi về handle của thiết bị ngữ
cảnh (handle to device context) cho ứng dụng của bạn. Bạn có thể dùng device context
như một giấy thông hà
nh để vẽ trên vùng client.

Vậy device context l
à gì?. Nó thực sự chỉ là một cấu trúc dữ liệu được duy trì bên trong
Windows bởi GDI . Một DC được kết hợp với một thiết bị hiển thị đặc thù như là màn
hình hay máy in. Đối với màn hình, một DC thường kết hợp với một cửa sổ riêng biệt trên
màn hình.


Một số giá
trị trong DC là các thuộc tính đồ họa như colors, font… Bạn có thể thay đổi
những giá trị mặc định nà
y bằng cách gọi các hàm GDI khác nhau. Các hàm GDI cho
phép bạn nhận các giá trị hiện hành của các thuộc tính này. Dĩ nhiên, còn có các hàm GDI
khác cho phép bạn thực sự vẽ vùng client của cửa sổ. Có thể xem DC như là môi trường
được thiết lập mặc định được HĐH chuẩn bị sẳn cho bạn. Bạn có thể thay đổi thiết lập
mặc định nếu bạn muốn.

Khi một chương trình cần vẽ, đầu tiên nó cần nhận một handl
e của một DC. Thông
thường, có 3 cách để nhận handle của DC:
 Sử dụng hàm BeginPaint và EndPaint để xử lý thông điệp WM_PAINT

Bạn sử dụng phương pháp này khi xử lý các thông điệp WM_PAINT. Hai hàm được yêu
cầu: BeginPaint và EndPaint. Hai hàm này yêu cầu handle cửa sổ, đưa vào thủ tục
window như một đối số và địa chỉ của biến cấu trúc này là ps và định nghĩa nó trong thủ
tục window như sau:
PAINTSTRUCT ps;

Cấu trúc PAINTSTRUCT được định nghĩa như sau:

typedef struct tagPAINTSTRUCT { // ps
HDC hdc; //handle c•a DC
BOOL fErase; //Cho bi•t background có b• xóa hay không
RECT rcPaint; //Cho bi•t t•a •• HCN tô v• l•i
BOOL fRestore; //dành riêng cho Windows s• d•ng
BOOL fIncUpdate; //dành riêng cho Windows s• d•ng
BYTE rgbReserved[32]; //dành riêng cho Windows s• d•ng
} PAINTSTRUCT;


Trong khi xử lý một thông điệp WM_PAINT, đầu tiên thủ tục Window gọi BegianPaint.
Hàm BeginPaint thường làm nền của vùng không hợp lệ bị xóa để chuẩn bị vẽ. Hàm cũng
điền vào các trường trong cấu trúc ps. Giá trị trả về từ BeginPaint là handle của DC. Nó
thường lưu trong một biến có tên là hdc. Bạn định nghĩa biến này trong thủ tục Window
như sau:
HDC hdc;
Người dịch: Benina (REA TEAM) Trang 2
Tổng hợp và hiệu chỉnh: NhatPhuongLe (VNCERT TEAM)
Iczelion’s Tutorial Win32 ASM Tutorial 4 : Painting with Text
Hiểu như thế nào về vùng không hợp lệ?

Khi cửa sổ ứng dụng bị người dùng tương tác (thay đổi kích thước, phóng to, thu nhỏ, đóng mở
các hộp thoại …), thì vùng client của cửa sổ sẽ bị thay đổi, nếu không vẽ lại vùng client kịp thời,
thì rất có thể vùng client sẽ bị loang lỗ (được gọi là invalid region). Windows thường xuyên kêu
chương trình của bạn “tô son điểm phấn” lại bằng cách phát thông điệp WM_PAINT. Để phản
hồi lại thông điệp này, thủ tục Window sẽ cho tô điểm lại cửa sổ tại những chỗ bị loang lỗ. Việc
này đòi hỏi thủ tục Window phải nhận được một DC, cung cấp những công cụ vẽ, quyền thâm
nhập vào thiết bị cũng như giấy phép thông hành cho phép vẽ cửa sổ.

Kiểu dữ liệu HDC được định nghĩa là một số nguyên 32-bit không dấu. Chương trình sau
đó có thể sử dụng các hàm GDI như TextOut, mà handle của DC yêu cầu. Việc gọi
EndPaint sẽ loại bỏ handle của DC.

Điển hình, việc xử lý thông điệp WM_PAINT có dạng như sau:

case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);

//S• d•ng các hàm GDI


EndPaint(hwnd, &ps);
return 0;

Thủ tục Window cần gọi BeginPaint và EndPaint như một cặp khi xử lý thông điệp
WM_PAINT. Nếu thủ tục Window không xử lý các thông điệp WM_PAINT, nó cần đưa
thông điệp WM_PAINT cho DefWindowProc, là thủ tục Window mặc định nằm trong
HĐH. DefWindowProc xử lý thông điệp WM_PAINT như sau:

case WM_PAINT:
BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
return 0;

Việc gọi liên tiếp BeginPaint và EndPaint sẽ làm hợp lệ vùng không hợp lệ trước đó.
Windows đặ một thông điệp WM_PAINT trong hàng đợi thông điệp vì một phần của
client không hợp lệ. Bạn không gọi BeginPaint và EndPaint (hay ValidateRect), HĐH sẽ
không hợp lệ vùng đó và sẽ gửi tiếp cho bạn một thông điệp WM_PAINT khác. Sự việc
sẽ làm treo chương trình vì không thể thoát.

 Sử dụng hàm GetDC để nhận ha
ndle và ReleaseDC để giải phóng handle của DC
khi xử lý các thông điệp khác WM_PAINT


Mặc dù tốt nhất là vẽ lại toàn bộ vùng client trong khi xử lý thông điệp WM_PAINT,
nhưng có thể bạn sẽ thấy hữu dụng hơn khi vẽ một phần vùng client trong quá trình xử
lý các thông điệp khác. Hoặc bạn có thể cần một handle của DC cho mục đích khác
như nhận thông tin về Device Context.
Người dịch: Benina (REA TEAM) Trang 3

Tổng hợp và hiệu chỉnh: NhatPhuongLe (VNCERT TEAM)
Iczelion’s Tutorial Win32 ASM Tutorial 4 : Painting with Text
Để nhận một handle của DC của vùng client của cửa sổ, bạn gọi GetDC để nhận
handle và gọi ReleaseDC khi bạn muốn giải phóng DC

hDC = GetDC(hWnd);
//X• lý …………

ReleaseDC(hWnd, hDC);

Cũng như BeginPaint và EndPaint, các hàm GetDC và ReleaseDC nên gọi theo cặp.
Khi bạn gọi GetDC trong khi xử lý một thông điệp. Bạn nên gọi ReleaseDC trước khi
bạn thoát thủ tục Window. Không nên gọi GetDC trong một thông điệp và ReleaseDC
trong một thông điệp khác.

Không như handle DC trả về BeginPaint, handle DC trả về từ GetDC có hình chữ nhật
xén toàn bộ vùng client. Bạn có thể vẽ trên bất kỳ phần nào của vùng client, không chỉ
đơn thuần là trên hình chữ nhật không hợp lệ (nếu thực sự có
hình chữ nhật không hợp
lệ). Không như BeginPaint, GetDC không hợp lệ hóa bất cứ vùng hợp lệ nào. Nếu bạn
cần hợp lệ hóa toàn bộ vùng client, bạn có thể gọi:

ValidateRect (hwnd, NULL);


 Gọi hàm GetWindowDC (CreateDC) và ReleaseDC.

hDC = GetWindowDC(hWnd);
// X• lý …………


ReleaseDC(hWnd, hDC);

Lưu ý
: Các hàm GetDC và BeginPaint trả về device context cho vùng client của cửa sổ,
riêng hàm GetWindowDC trả về device context của toàn bộ cửa sổ kể cả thanh tiêu đề,
menu, thanh cuộn… và tất nhiên là cả vùng client. Để vẽ ra ngoài vùng làm việc
(client area), phải chặn thông điệp WM_NCPAINT( NC: None Client).

Một điều mà bạn phải nhớ là, sau khi bạn nhận được handle của DC, bạn chỉ sử dụng DC
cho việc xử lý một thông điệp duy nhất, tức là không được nhận handle ở t
hông điệp này
mà giải phóng nó ở một thông điệp khác.

HĐH sẽ gởi thông điệp WM
_PAINT đến cửa sổ để vẽ lại vùng client của nó. HĐH không
lưu nội dung của vùng client của một cửa số. Thay vào đó, khi có một sự kiện xảy ra, thì
nó cho phép vẽ lại vùng client (như trường hợp vùng client của cửa sổ này bị che bởi
vùng client của một cửa sổ khác
), HĐH sẽ đặt thông điệp WM_PAINT trong hàng đợi
thông điệp. Nó chịu trách nhiệm vẽ lại vùng client của cửa sổ. Bạn phải cung cấp các
thông tin để HĐH biết cửa sổ muốn vẽ lại vùng client như thế nào trong phần
WM_PAINT của thủ tục window, vì vậy thủ tục window sẽ vẽ lại vùng client khi thông
điệp WM_PAINT được tiếp nhận.

Người dịch: Benina (REA TEAM) Trang 4
Tổng hợp và hiệu chỉnh: NhatPhuongLe (VNCERT TEAM)
Iczelion’s Tutorial Win32 ASM Tutorial 4 : Painting with Text
Khái niệm khác mà bạn phải tìm hiểu đến là thuật ngữ hình chữ nhật không hợp lệ
(invalid rectangle). HĐH định nghĩa một hình chữ nhật không hợp lệ là một vùng hình
chữ nhật nhỏ nhất trong vùng client cần được vẽ lại. Khi HĐH phát hiện ra một hình chữ

nhật không hợp lệ trong vùng client của một cửa sổ, nó sẽ gởi thông điệp WM_PAINT
đến cửa sổ đó. Để phản hồi lại t
hông điệp WM_PAINT này, handle của được chứa trong
một cấu trúc PAINTSTRUCT, trong số những trường của cấu trúc này, có tọa độ của
hình chữ nhật không hợp lệ. Bạn gọi hàm BeginPaint trong việc phản hồi thông điệp
WM_PAINT để hợp lệ hóa hình chữ nhật không hợp lệ. Nếu không thực hiện thông
điệp WM_PAINT, thì ít nhất bạn cũng phải gọi hàm De
fWindowProc hay ValidateRect
hợp lệ lệ hóa hình chữ nhật ko hợp lệ, nếu không thì HĐH sẽ gởi cho bạn thông điệp
WM_PAINT lặp đi lặp lại nhiều lần.

Để phản hồi lại thông điệp W
M_PAINT, bạn cần thực hiện các bước sau:

 Lấy một handle của DC bằng hàm BeginPaint.
 Vẽ vùng client.
 Giải phóng handle của DC bằng hàm EndPaint

Chú ý rằng, bạn không phải làm hợp lệ hóa hình chữ nhật ko hợp lệ. Nó được làm một
cách tự động bởi hàm
BeginPaint. Giữa cặp BeginPaint vàEndPaint, bạn có thể gọi bất kỳ
hàm GDI để vẽ vùng client của bạn. Gần như tất cả chúng đều cần handle của device
context như một tham số.

Chúng ta sẽ viết một chương trình hiển thị dòng chữ “Win32 assembly is great and easy!”
ở giữa vùng client.

.386
.model flat,stdcall
option casemap:none


WinMain proto :DWORD,:DWORD,:DWORD,:DWORD

include windows.inc
include user32.inc
include kernel32.inc
includelib user32.lib
includelib kernel32.lib

.data

ClassName db "SimpleWinClass",0
AppName db "Our First Window",0
OurText db "Win32 assembly is great and easy!",0

.data?

hInstance HINSTANCE ?
CommandLine LPSTR ?

.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke GetCommandLine
Người dịch: Benina (REA TEAM) Trang 5
Tổng hợp và hiệu chỉnh: NhatPhuongLe (VNCERT TEAM)

×