2014-11-07 12 views
5

Tôi đang tạo Hộp thoại bằng cách sử dụng CreateDialog.DrawText sử dụng FONT và SetBkMode trong cửa sổ Hộp thoại

trong proc thoại tôi làm một số bản vẽ của văn bản trong WM_PAINT:

function DialogProc(hDlg: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): BOOL; stdcall; 
... 
case Msg of 
    WM_PAINT: 
    begin 
     dc := BeginPaint(hDlg, ps);  
     bkmodePrev := SetBkMode(dc, TRANSPARENT); 
     hfnt := SendMessage(hDlg, WM_GETFONT, 0, 0); 
     hfntPrev := SelectObject(dc, hfnt); 
     DrawTextW(dc, 'Text', -1, R, DT_SINGLELINE or DT_CENTER or DT_VCENTER); 
     SelectObject(dc, hfntPrev); 
     // SetBkMode(dc, bkmodePrev); // do I need this? 
     EndPaint(hDlg, ps); 
     Result := True; 
    end; 
    end; 
... 

Bây giờ câu hỏi là, tôi làm việc đó đúng với phông chữ, có nghĩa là, đây là cách chính xác để có được phông chữ xử lý hộp thoại bằng cách sử dụng SendMessage(hDlg, WM_GETFONT, 0, 0) và khôi phục bằng SelectObject(dc, hfntPrev)? Tôi có cần khôi phục mã BkMode cũ của bkmodePrev bằng cách sử dụng SetBkMode(dc, bkmodePrev); không? hoặc sẽ EndPaint làm điều đó cho tôi?

P.S: Tôi có cần giải phóng DC không?

Trả lời

5

Tôi có làm đúng với phông chữ không?

Có.

Tôi có cần khôi phục BkMode cũ của bkmodeprev bằng cách sử dụng SetBkMode(dc, bkmodeprev) hoặc EndPaint làm điều đó cho tôi không?

EndPaint sẽ không khôi phục chế độ kết hợp nền cho bạn. Nhưng EndPaint không phá hủy bối cảnh thiết bị để nó không cần phải được khôi phục. Tuy nhiên, theo quan điểm của tôi, thực hành tốt nhất là khôi phục chế độ hòa trộn nền bất cứ khi nào bạn thay đổi nó. Sau đó, nếu bạn mở rộng mã trong tương lai, bạn sẽ không ngạc nhiên. Nhưng đó thực sự là một sở thích. Bạn có thể lập trường khác.

Tôi có cần giải phóng DC không?

Không, cuộc gọi đến EndPaint đủ.


Tôi sẽ viết những dòng này như sau:

dc := BeginPaint(hDlg, ps);  
bkmodeprev := SetBkMode(dc, TRANSPARENT); 
hfnt := SendMessage(hDlg, WM_GETFONT, 0, 0); 
hfntPrev := SelectObject(dc, hfnt); 
DrawTextW(dc, 'Text', -1, R, DT_SINGLELINE or DT_CENTER or DT_VCENTER); 
SelectObject(dc, hfntPrev); 
SetBkMode(dc, bkmodeprev); 
EndPaint(hDlg, ps); 

Mặc dù, người ta có thể cho rằng nó sẽ là tốt hơn để bao gồm một số kiểm tra lỗi.


Như được nêu trong các nhận xét bạn cần cung cấp giá trị trả lại cho thông báo WM_PAINT. Từ docs:

Nếu các thủ tục hộp thoại xử lý một thông điệp rằng đòi hỏi một giá trị trả về cụ thể, thủ tục hộp thoại nên thiết lập giá trị lợi nhuận mong muốn bằng cách gọi SetWindowLong (hwndDlg, DWL_MSGRESULT, LRESULT) ngay lập tức trước khi trở về TRUE. Lưu ý rằng bạn phải gọi SetWindowLong ngay lập tức trước khi trở về TRUE; làm như vậy trước đó có thể dẫn đến giá trị DWL_MSGRESULT bị ghi đè bởi một thông điệp hộp thoại lồng nhau.

+1

cảm ơn David. như bình thường câu trả lời của bạn là vàng :) – kobik

+2

EndPaint sẽ phá hủy bối cảnh thiết bị khiến chế độ nền được mặc định (OPAQUE) cho vòng thời gian tiếp theo. Không cần phải khôi phục lại, chỉ các DC 'lớp' và 'riêng tư' duy trì trạng thái. –

+2

Vì anh ta đang xử lý 'WM_PAINT'in một hộp thoại, anh ta cần 'SetWindowLongPtr (hDlg, DWLP_MSGRESYLT, (LONG_PTR) 0);' sau khi 'EndPaint' gọi.Chỉ sau đó anh mới có thể trả lại 'TRUE' hoặc có thể tôi đã sai? – AlwaysLearningNewStuff

Các vấn đề liên quan