Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 73 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
73
Dung lượng
1,25 MB
Nội dung
Bài GIAO TIẾP THIẾT BỊ ðỒ HỌA Phần hệ thống Microsoft Windows liên quan tới việc thể ñồ họa thiết bị giao tiếp hình, máy in ñược gọi phần Giao tiếp Thiết bị ðồ họa (GDI – Graphics Device Interface) ðây chế mà thơng qua lập trình viên thao tác thể thông tin, liệu cách trực quan ứng dụng Trong học này, tìm hiểu cách xuất văn bản, vẽ ñường thẳng, tô màu,… thông qua hàm API GDI tương ứng mà Windows cung cấp 4.1 TỔNG QUAN VỀ GDI Chúng ta cần biết khái niệm, kỹ thuật GDI Microsoft Windows nhiều Vì khơng chế để lập trình viên thao tác văn bản, hình ảnh, mà từ đầu chế mà Windows phải thực ñể thể giao diện chung mình: cách trình bày menu, icon, cursor,… Tuy vậy, phạm vi mơn học, khơng phân tích Windows tổ chức ñối tượng ñồ họa, mà tìm hiểu hàm, cấu trúc liệu đồ họa gì, cách thức ñể thể chúng ứng dụng Windowsbased nào… 4.1.1 GDI Thiết bị Ngữ cảnh Xét góc độ lập trình, GDI tập hợp hàng trăm hàm (function) kiểu liệu, macro, cấu trúc mà Microsoft ñịnh nghĩa ñể xây dựng giao diện hệ ñiều hành Windows Cơ chế ñồ họa Windows 98 Microsoft Windows NT ñược quản lý thông qua hàm liên kết từ thư viện GDI32.DLL Trên Windows 98, thư viện GDI32.DLL sử dụng hàm từ thư viện GDI.EXE 16-bit ñể thực thao tác cài ñặt thật hàm Trên Windows NT, thư viện GDI.EXE dùng cho chương trình dạng 16-bit ðiểm cần ý việc Windows sử dụng thư viện ñể thể liệu ñồ họa lên thiết vị vật lý cụ thể (video display, printer) Câu trả lời thể qua mơ hình hình 4.1 sau: Hình 4.1 Mơ hình hoạt động GDI Như thể mơ hình, ứng dụng Windows khơng thật thao tác đến thiết bị xuất vật lý, mà thao tác ñến ñối tượng logic, gọi Thiết bị Ngữ cảnh (DC - Device Context) Và vậy, mức lập trình, cần biết làm ñể gọi hàm GDI lên đối tượng DC mà thơi – tìm hiểu dạng hàm GDI cách gọi hàm thao tác ñối tượng ñồ họa hai phần 74 Cũng từ mơ hình, hiểu mà ứng với thiết bị vật lý card hình, máy in,… cần phài cài ñặt trình ñiều khiển thiết bị (driver) tương ứng sử dụng Windows Các driver có nhiệm vụ chuyển lệnh GDI thành mã lệnh cách truy cập mà thiết bị phần cứng tương ứng hiểu thực ñúng theo yêu cầu ứng dụng Và vậy, lập trình mà không quan tâm tới việc thiết bị máy in hay video display sử dụng Vì vậy, GDI cịn gọi chế đồ họa độc lập thiết bị (device-independent graphics) Ở trên, có nói ñến Thiết bị Ngữ cảnh, Thiết bị Ngữ cảnh gì, cách thức lập trình thao tác Thiết bị Ngữ cảnh nào? Ta ñịnh nghĩa sau, Thiết bị Ngữ cảnh bao gồm tập hợp “thuộc tính” xác định cách thức hàm GDI thao tác thiết bị Tập thuộc tính tương ứng cấu trúc đối tượng gọi ñối tượng ñồ họa (xem phần 4.1.3) Khi ta gọi hàm GDI ñể thực thao tác đồ họa đó, ví dụ dùng hàm LineTo để vẽ đường thẳng đến vị trí DC, Windows dùng thơng tin bút vẽ (pen) màu sắc, ñộ dày nét vẽ,… sẵn có đối tượng đồ họa để vẽ Trong trường hợp muốn vẽ với màu sắc, kiểu vẽ,… khác, ta việc thay ñổi thơng số đối tượng trước thực thao tác vẽ Chúng ta tìm hiểu cách thao tác số ñối tượng ñồ họa bút vẽ (pen), chổi tô (brush) ảnh bitmap phần tiếp sau 4.1.2 Các dạng hàm GDI Dựa vào mục đích sử dụng, tập hợp hàm GDI phân thành số loại sau: Các hàm nhận (hoặc tạo) giải phóng (hoặc hủy) ñối tượng DC Như ñã thấy ví dụ ñầu tiên, để xuất dịng chữ biến szHello hình, ta dùng hàm DrawText để vẽ lên đối tượng hdc ðối tượng nhận ñược qua hàm BeginPaint giải phóng hàm EndPaint bên thơng điệp WM_PAINT Chúng ta nói rõ thêm hàm phần 4.1.4 Các hàm lấy thông tin DC Trong số ứng dụng, cần xác định số thơng tin DC kích thước DC tính theo pixel tính theo milimet, số lượng bút vẽ, chổi tơ,… DC ta dùng hàm Tuy nhiên, với phạm vi môn học khơng tìm hiểu hàm lấy thơng tin DC Các hàm thực thao tác vẽ ðể xuất văn bản, vẽ ñường thẳng, tơ hình trịn,… GDI cung cấp cho số hàm tương ứng TextOut, LineTo, Ellipse Trong phần tìm hiểu số hàm thơng qua ví dụ tương ứng Các hàm thiết lập lấy thuộc tính DC Một “thuộc tính” DC xác định ñặc tính liên quan ñến dạng thức thực thao tác vẽ Thơng qua số hàm có liên quan, ta thiết lập lấy xem thuộc tính đó, chẳng hạn ta dùng hàm SetTextColor để thay ñổi màu sắc văn ñược vẽ hình hàm DrawText Các hàm thao tác “ñối tượng” GDI Trong phần tiếp theo, tìm hiểu kỹ “đối tượng” mà thơng qua chúng, thay đổi cách thể thơng tin đồ 75 họa khác lên DC Mặc định DC ln “có” đối tượng GDI với “thơng số” đó, thay đổi “thơng số” chúng muốn thay ñổi kết thể thao tác vẽ Chẳng hạn, với DC ta thể ñộ dày màu sắc nét vẽ ñường thẳng thơng qua đối tượng bút vẽ (pen), ta muốn vẽ với nét vẽ khác phải dùng ñối tượng bút vẽ Các hàm mà ñang ñề cập ñây giúp “thay ñổi” ñối tượng bút vẽ ñối tượng ñồ họa khác DC 4.1.3 Các ñối tượng ñồ họa Các dạng ñồ họa thể hình máy in phân thành số dạng, gọi ñối tượng “cơ bản”, dựa ñặc ñiểm riêng chúng Các ñối tượng ñường cung ðường (line) thành phần tảng hệ thống ñồ họa vector GDI hỗ trợ dạng đường đường thẳng, hình chữ nhật, ellipse, cung ellipse, ñường cong Bezier, polyline,… Các dạng ñường ñược gọi vẽ thao tác vẽ sử dụng thơng tin bút vẽ (pen) chọn DC Các đối tượng vùng tơ Với vùng khép kín tạo đường cung, ta tơ với đối tượng chổi tô (brush) DC Các dạng tô gồm có tơ đặc (solid), tơ theo mẫu (pattern) phủ ñầy cách lặp lại ảnh bitmap ñó tồn vùng tơ ðối tượng ảnh bitmap Một bitmap mảng chữ nhật bit liệu tương ứng pixel ảnh thể thiết bị hiển thị Khác với ñối tượng ñường, bitmap thành phần tảng dạng ñồ họa ñiểm (raster graphics) Thơng thường, nhắc đến bitmap, dễ dàng nghĩ đến đối tượng ảnh thực tế thể thể thiết bị hiển thị Tuy nhiên, bên cạnh đó, đối tượng icon, cursor,… ñối tượng bitmap GDI hỗ trợ hai dạng bitmap, dạng thứ bitmap phụ thuộc thiết bị (device-dependent), ñây dạng bitmap gắn liền với phiên ñầu tiên Windows, ñược dùng ứng dụng sau Trong phạm vi môn học, thao tác dạng bitmap Dạng thứ hai ñược gọi bitmap ñộc lập thiết bị (DIB – Device Independent Bitmap), ñược ñưa vào từ phiên Windows 3.0 Dạng bitmap lưu (theo cấu trúc riêng) nạp vào ứng dụng từ tập tin Khi lập trình, Windows hỗ trợ chuyển ñổi hai dạng bitmap với (với vài “mất mát” thông tin) ðối tượng văn Khơng giống đối tượng đồ họa trên, ñối tượng văn ñối tượng phức tạp ðể thể văn dạng khác nhau, cần sử dụng cấu trúc font ñược ñịnh nghĩa trước Các cấu trúc tương đối lớn Trong phạm vi mơn học, không thao tác dạng font chữ, mà bàn ñến cách gọi hàm ñể thể nội dung văn thiết bị xuất Ngồi đối tượng trên, cịn có đối tượng GDI khác bao gồm mapping modes and transforms (chế ñộ ánh xạ ñiểm ảnh), metafiles, regions (vùng), paths (tập hợp ñường), clipping (vùng cắt), palettes (bảng màu) printing (ñối tượng in ấn) Trong phạm vi 76 môn học khơng tìm hiểu thao tác với đối tượng Hình 4.2 Quy trình thực thao tác đồ họa DC hiển thị 4.1.4 Quy trình thao tác đối tượng đồ họa Với mơ hình hình 4.1, ñã nắm ñược cách mà Windows thực thao tác đồ họa, mơ hình lý thuyết Trong phần giải cách cài ñặt code thao tác ñồ họa theo quy trình chung thể mơ hình hình 4.2 Cơng việc cần phải làm có DC cửa sổ cần thể liệu đồ họa, sau tất hàm ñồ họa ñều thao tác lên DC Thật ra, quy trình mà tìm hiểu nói đến việc thể liệu thiết bị hiển thị video, thao tác DC dạng thiết bị Nếu xét DC Windows cung cấp cho bốn loại khác nhau: DC hiển thị (Display DC), DC vùng nhớ (Memory DC), DC in ấn (Printer DC) DC thông tin (Information DC) Tuỳ theo yêu cầu phải quản lý thao tác mà cần dùng dạng DC khác thông qua hàm khác ðối với môn học này, thao tác hai dạng DC liên quan tới việc hiển thị liệu lên thiết bị video DC hiển thị DC vùng nhớ Với thao tác ñồ họa xuất văn (xem phần 4.2) thao tác bút vẽ, chổi tô (xem phần 4.3), thao tác lên DC hiển thị Thao tác nhận giải phóng DC hiển thị thực theo hai cách: Dùng thơng điệp WM_PAINT Thơng điệp WM_PAINT gởi hệ thống ứng dụng yêu cầu thực thao tác vẽ (paint) lại vùng cửa sổ ứng dụng Và vậy, ta muốn thể kết ñồ họa lên cửa sổ ứng dụng ta việc viết code thơng điệp Trong trường hợp này, để lấy DC ta dùng hàm BeginPaint để giải phóng DC ta dùng hàm EndPaint HDC BeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint); BOOL EndPaint(HWND hWnd, CONST PAINTSTRUCT *lpPaint); Với hWnd danh cửa sổ cần vẽ, lpPaint trỏ ñến cấu trúc PAINSTRUCT xác định thơng tin vẽ Khơng dùng WM_PAINT Bất kỳ đâu ứng dụng, cần có danh hWnd cửa sổ, ta dùng hàm GetDC GetWindowDC để nhận DC, sau dùng hàm ReleaseDC để giải phóng DC HDC GetDC(HWND hWnd); HDC GetWindowDC(HWND hWnd); int ReleaseDC( HWND hWnd, HDC hDC); 77 Hàm GetDC GetWindowDC khác việc hàm GetDC trả DC vùng client area, hàm GetWindowDC trả DC toàn cửa sổ, bao gồm tiêu đề, menu Mỗi DC có sẵn đối tượng GDI bên Khi thực thao tác vẽ đó, Windows sử dụng đối tượng mặc định có Tuy nhiên, ta lập trình tạo đối tượng khác Trong phần tiếp theo, tìm hiểu cách tạo lập số đối tượng thơng qua ví dụ Một đối tượng GDI muốn đưa vào DC, ta dùng hàm SelectObject, hàm thao tác chung cho tất ñối tượng GDI (HGDIOBJ), lập trình thao tác cho dạng đối tượng cụ thể đó, ta cần ép kiểu (cast) ñối tượng tương ứng (xem thêm ví dụ) Sau sử dụng xong ñối tượng GDI, ta việc dùng hàm DeleteObject ñể huỷ bỏ HGDIOBJ SelectObject(HDC hDC, HGDIOBJ hGDIObj); BOOL DeleteObject(HGDIOBJ hObject); 4.2 THAO TÁC VĂN BẢN Chúng ta tìm hiểu thao tác văn thơng qua chương trình minh họa cách thể dịng chữ “Hello World!” lên hình ứng dụng với màu sắc vị trí dịng chữ người dùng chọn từ menu 4.2.1 Tạo lập project VanBan tài nguyên menu Với project trước ñây, ñã biết tạo ứng dụng Win32 Application chọn dạng tạo A typical “Hello World!” application, chương trình thực thể dịng chữ “Hello World!” màu ñen nằm vùng làm việc (client area) Ta tạo lập project VanBan theo dạng này, sau vào ResourceView chọn menu IDC_VANBAN ñể thêm số menu item sau: Thêm popup menu Color với item Black (IDM_BLACK), Red (IDM_RED), Green (IDM_GREEN) Blue (IDM_BLUE) Thêm popup menu Alignment với item Left (IDM_LEFT), Center (IDM_CENTER) Right (IDM_RIGHT) 4.2.2 Viết code xử lý cho ứng dụng Như tìm hiểu 2, để chương trình thực thao tác người dùng chọn menu item, ta việc vào chặn ñịnh danh chúng thông qua giá trị LOWORD(wParam) thông ñiệp WM_COMMAND viết code thao tác tương ứng Tuy nhiên ứng dụng này, thao tác thể lại văn lên DC ứng dụng người dùng chọn menu item màu sắc dạng canh lề, trường hợp thực thao tác qua thơng điệp WM_PAINT Do ñó, ñể làm ñiều ta lợi dụng hàm InvalidateRect với mục đích hàm “gởi” u cầu thực thơng điệp WM_PAINT cửa sổ hWnd tương ứng 78 BOOL InvalidateRect(HWND hWnd, CONST RECT* lpRect, BOOL bErase); Xét ñoạn code thực thao tác xuất văn thơng điệp WM_PAINT ðể xuất đoạn văn DC ta dùng hàm DrawText, hàm thể chuỗi lpString lên vùng hình chữ nhật lpRect hDC với dạng canh lề thiết lập qua uFormat int DrawText(HDC hDC, LPCTSTR lpString, int nCount, LPRECT lpRect, UINT uFormat); Với ứng dụng này, ta dùng ba dạng canh lề với giá trị uFormat DT_LEFT, DT_CENTER, DT_RIGHT cho yêu cầu thể văn trái, bên phải lpRect Như vậy, lần ta chọn menu item canh lề ta phải chuyển ñược thông số tương ứng ñến cho uFormat Trong trường hợp ta dùng biến phụ dạng toàn cục (global), tĩnh (static) biến nAlign bên hàm WndProc Về việc thay ñổi màu văn bản, ta thực tương tự, sử dụng biến crColor với màu mặc ñịnh màu ñen RGB(0,0,0) Hàm SetTextColor dạng hàm thay đổi thuộc tính màu sắc văn cần xuất DC COLORREF SetTextColor(HDC hdc, COLORREF crColor); Với thao tác trên, ta có ñoạn code hàm WndProc ứng dụng VanBan tập tin VanBan.cpp sau (các phần khác tập tin khơng cần thay đổi) 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; TCHAR szHello[MAX_LOADSTRING]; LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING); COLORREF crOldColor; static COLORREF crColor = RGB(0, 0, 0); static UINT nAlign = DT_CENTER; switch (message) { case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // Parse the menu selections: switch (wmId) { case IDM_BLACK: crColor = RGB(0, 0, 0); break; case IDM_RED: crColor = RGB(255, 0, 0); break; case IDM_GREEN: crColor = RGB(0, 255, 0); break; case IDM_BLUE: crColor = RGB(0, 0, 255); break; case IDM_LEFT: nAlign = DT_LEFT; 79 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 break; case IDM_CENTER: nAlign = DT_CENTER; break; case IDM_RIGHT: nAlign = DT_RIGHT; break; case IDM_ABOUT: DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } InvalidateRect(hWnd, NULL, TRUE); break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: Add any drawing code here crOldColor = SetTextColor(hdc, crColor); RECT rt; GetClientRect(hWnd, &rt); DrawText(hdc, szHello, strlen(szHello), &rt, nAlign); SetTextColor(hdc, crOldColor); EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } 4.3 THAO TÁC ðỐI TƯỢNG BÚT VẼ, CHỔI TƠ So với quy trình chung thực thao tác đối tượng đồ họa hình 4.2, việc thể văn mà vừa thực khơng nói đến việc tạo lập đưa ñối tượng GDI (nếu có font chữ) vào DC mà sử dụng thơng tin mặc định Vì thế, phần tìm hiểu thêm thao tác đối tượng GDI, đồng thời tìm hiểu cách xuất ñối tượng ñường, cung vùng tơ thiết bị hiển thị 80 Hình 4.3 Kết sau người dùng chọn chức Ellipse Chúng ta thực ví dụ ứng dụng cho phép người dùng chọn menu ñể thể vùng làm việc đường thẳng, hình chữ nhật, ellipse với kích thước cho trước màu sắc chọn từ menu - xem hình 4.3 4.2.1 Tạo lập project VeHinh tài nguyên menu Tương tự ứng dụng văn bản, tạo lập project Win32 Application với tên VeHinh, dạng A typical “Hello World!” application Sau chọn menu IDC_VEHINH ResourceView thêm menu item sau: Thêm popup menu Shape với item Line (IDM_LINE), Rectangle (IDM_RECTANGLE), Ellipse (IDM_ELLIPSE) Thêm popup menu Color với item Black (IDM_BLACK), Red (IDM_RED), Green (IDM_GREEN) Blue (IDM_BLUE) 4.3.2 Viết code xử lý cho ứng dụng Tương tự ứng dụng VanBan, viết code thơng điệp WM_COMMAND ñể xử lý cho thao tác menu item Ta dùng biến tĩnh crColor kiểu COLORREF ñể lưu giá trị màu cần vẽ; dùng biến int nShape ñể lưu dạng hình vẽ, với giá trị đặt 1, 2, ứng với dạng hình vẽ đường thẳng, hình chữ nhật ellipse Sau thiết lập giá trị dùng để vẽ hình, ứng dụng VanBan, ta dùng hàm InvalidateRect để kích hoạt thơng điệp WM_PAINT cửa sổ Quy trình bên thơng điệp WM_PAINT mơ hình hình 4.2 ðầu tiên ứng dụng lấy DC hàm BeginPaint, sau tạo lập bút vẽ hPen chổi tơ hBrush theo màu chọn (mặc định màu ñen) ñưa vào DC hàm SelectObject Tiếp theo ứng dụng vào giá trị nShape ñể thực thao tác vẽ Ở ñây ta dùng số hàm API ñã ñược 81 Windows cung cấp LineTo, Rectangle,… Trong trường hợp thực thao tác đồ họa khác ta có hàm khác, cần tra cứu MSDN Cuối cùng, ta chọn lại ñối tượng GDI ban ñầu, hủy ñối tượng tạo lập trước hàm DeleteObject, kết thúc thơng điệp WM_PAINT với hàm EndPaint Sau liệt kê prototype hàm dùng ứng dụng VeHinh Hàm CreatePen tạo lập ñối tượng bút vẽ HPEN theo kiểu vẽ fnPenStyle (PS_SOLID, PS_DASH, PS_DOT,…), ñộ dày nét vẽ nWidth màu vẽ crColor HPEN CreatePen(int fnPenStyle, int nWidth, COLORREF crColor); Hàm CreateSolidBrush tạo lập đối tượng chổi tơ đặc (solid) với màu tơ crColor HBRUSH CreateSolidBrush(COLORREF crColor); Hàm SelectObject đưa đối tượng HGDIOBJ (là bút vẽ HPEN, chổi tơ HBRUSH, font chữ HFONT, …) vào DC trả ñối tượng cũ tương ứng DC HGDIOBJ SelectObject(HDC hdc, HGDIOBJ hgdiobj); Hàm DeleteObject hủy ñối tượng GDI ñã tạo lập trước khơng cần dùng BOOL DeleteObject(HGDIOBJ hObject); Hàm GetClientRect nhận thơng tin tọa cửa sổ hWnd chuyển thơng tin vào cấu trúc hình chữ nhật lpRect BOOL GetClientRect(HWND hWnd, LPRECT lpRect); Hàm MoveToEx thiết lập lại vị trí điểm vẽ ñến tọa ñộ X, Y trả ñiểm vẽ cũ vào biến lpPoint BOOL MoveToEx(HDC hdc, int X, int Y, LPPOINT lpPoint); Hàm LineTo sử dụng thông số bút vẽ ñể vẽ ñường thẳng từ vị trí điểm vẽ đến nXEnd, nYEnd BOOL LineTo(HDC hdc, int nXEnd, int nYEnd); Cuối hàm vẽ hình chữ nhật ellipse nội tiếp hình chữ nhật có vị trí góc trái, trên, phải xác ñịnh tham số nLeftRect, nTopRect, nRightRect, nBottomRect BOOL Rectangle(HDC hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); BOOL Ellipse(HDC hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); Và ñây ñoạn code hàm WndProc ứng dụng VeHinh LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; 82 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 static int nShape = 1; // 1: Line; 2: Rectangle; 3: Ellipse static COLORREF crColor = RGB(0, 0, 0); HPEN hPen, hOldPen; HBRUSH hBrush, hOldBrush; RECT rt; POINT ptCenter; switch (message) { case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // Parse the menu selections: switch (wmId) { case IDM_LINE: nShape = 1; break; case IDM_RECTANGLE: nShape = 2; break; case IDM_ELLIPSE: nShape = 3; break; case IDM_BLACK: crColor = RGB(0, 0, 0); break; case IDM_RED: crColor = RGB(255, 0, 0); break; case IDM_GREEN: crColor = RGB(0, 255, 0); break; case IDM_BLUE: crColor = RGB(0, 0, 255); break; case IDM_ABOUT: DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } InvalidateRect(hWnd, NULL, TRUE); break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); hPen = CreatePen(PS_SOLID, 1, crColor); hBrush = CreateSolidBrush(crColor); hOldPen = (HPEN)SelectObject(hdc, hPen); hOldBrush = (HBRUSH)SelectObject(hdc, hBrush); GetClientRect(hWnd, &rt); ptCenter.x = (rt.left+rt.right)/2; ptCenter.y = (rt.top+rt.bottom)/2; switch(nShape) { case 1: MoveToEx(hdc, ptCenter.x-100, ptCenter.y-50, NULL); LineTo(hdc, ptCenter.x+100, ptCenter.y+50); break; 83 Theo nghĩa ñơn giản, kiến trúc Document-View tách rời liệu thực tế với cách nhìn người dùng liệu Lợi ích rõ ràng kiến trúc cho phép thể ñược nhiều khung nhìn khác với liệu Giả dụ có tài liệu chứa số liệu giá chứng khốn (stock) lưu đĩa Và ta muốn hiển thị liệu hai dạng thức bảng biểu (table) biểu ñồ (chart) ứng dụng Người dùng cập nhật giá trị bảng biểu khung nhìn, họ xem kết dạng biểu đồ khung nhìn khác Trong ứng dụng sử dụng thư viện MFC, tài liệu khung nhìn thể đại diện (instance) dạng lớp C++ Hình 6.6 minh họa cho yêu cầu vừa nêu trên, thể ba đối tượng liệu cho cơng ty AT&T, IBM GM dạng lớp ñối tượng CStockDoc Cả ba đối tượng tài liệu có khung nhìn bảng biểu kèm, ta cần thêm khung nhìn dạng cột cho cơng ty AT&T Ta có bốn đối tượng dạng lớp CStockTableView CStockChartView Hình 6.6 Mối liên hệ Document-View Lớp tài liệu sở ứng dụng cài ñặt sẵn chế hỗ trợ việc thao tác liệu tập tin Chúng ta kết hợp menu item File Open File Save theo cấu trúc thông thường ứng dụng ñể gọi hàm mở hộp thoại tương ứng Trong ứng dụng MFCExample, ta nhận thấy ñể mở hộp thoại File Open File Save, sử dụng hàm mặc ñịnh lớp mà không cần phải thao tác hộp thoại thơng dụng tìm hiểu Win32 Application Khi đó, với liệu lớp tài liệu (document class) có được, cần hiển thị liệu lên cửa sổ đó, ta việc gọi nhận liệu hiển thị hình theo chế mà cửa sổ hỗ trợ Tất thao tác giao tiếp tài liệu, khung nhìn, cửa sổ đối tượng ứng dụng ñều 132 ñược quản lý chặt chẽ thông qua hàm ảo thư viện MFC Chúng ta tìm hiểu kiến trúc Document-View thơng qua ví dụ nạp ảnh bitmap từ tập tin (.bmp) hiển thị lên cửa sổ ứng dụng MFCExample Các bạn áp dụng hiểu biết thao tác đồ họa GDI thao tác bàn phím (keyboard) để cài ñặt cho ứng dụng Như ñã trình bày 4, ñối tượng ảnh bitmap Windows ñược phân thành hai dạng bitmap phụ thuộc thiết bị (DDB – Device Dependent Bitmap) bitmap ñộc lập thiết bị (DIB – Device Independent Bitmap), ñã làm quen thao tác nạp ảnh bitmap từ resource tạo ñối tượng DDB HBITMAP hiển thị lên hình Tương tự vậy, ñây thực việc hiển thị ảnh bitmap, dạng DIB ñược ñọc từ tập tin ảnh ðể làm ñiều này, khơng đơn giản gọi hàm LoadBitmap, mà cần ñọc ảnh theo cấu trúc ñịnh dạng ảnh tập tin Và ảnh đối tượng ñộc lập thiết bị, ñó ta cần sử dụng số hàm ñược cài ñặt riêng Rất may Microsoft cung cấp số hàm ví dụ MSDN, kế thừa chúng cho ứng dụng minh họa 6.3.1 Thư viện DIBAPI Microsoft Ta tạo project tập tin DIBAPI.h, DIBAPI.cpp MyFile.cpp, cài ñặt hàm liên quan tới việc thao tác liệu tập tin ảnh ñối tượng ảnh vùng nhớ Tập tin DIBAPI.h ñịnh nghĩa ñối tượng ảnh HDIB prototype số hàm thao tác thông tin ảnh (cài ñặt tập tin DIBAPI.cpp) thao tác tập tin ảnh (cài ñặt tập tin MyFile.cpp) 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 // // // // // // // // // // // dibapi.h This is a part of the Microsoft Foundation Classes C++ library Copyright (C) 1992-1998 Microsoft Corporation All rights reserved This source code is only intended as a supplement to the Microsoft Foundation Classes Reference and related electronic documentation provided with the library See these sources for detailed information regarding the Microsoft Foundation Classes product #ifndef _INC_DIBAPI #define _INC_DIBAPI /* Handle to a DIB */ DECLARE_HANDLE(HDIB); /* DIB constants */ #define PALVERSION 0x300 /* DIB Macros*/ #define IS_WIN30_DIB(lpbi) ((*(LPDWORD)(lpbi)) == sizeof(BITMAPINFOHEADER)) #define RECTWIDTH(lpRect) ((lpRect)->right - (lpRect)->left) #define RECTHEIGHT(lpRect) ((lpRect)->bottom - (lpRect)->top) 133 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 // // // // WIDTHBYTES performs DWORD-aligning of DIB scanlines The "bits" parameter is the bit count for the scanline (biWidth * biBitCount), and this macro returns the number of DWORD-aligned bytes needed to hold those bits #define WIDTHBYTES(bits) (((bits) + 31) / 32 * 4) /* Function prototypes */ BOOL WINAPI PaintDIB (HDC, LPRECT, HDIB, LPRECT, CPalette* pPal); BOOL WINAPI CreateDIBPalette(HDIB hDIB, CPalette* cPal); LPSTR WINAPI FindDIBBits (LPSTR lpbi); DWORD WINAPI DIBWidth (LPSTR lpDIB); DWORD WINAPI DIBHeight (LPSTR lpDIB); WORD WINAPI PaletteSize (LPSTR lpbi); WORD WINAPI DIBNumColors (LPSTR lpbi); HGLOBAL WINAPI CopyHandle (HGLOBAL h); BOOL HDIB WINAPI SaveDIB (HDIB hDib, CFile& file); WINAPI ReadDIBFile(CFile& file); #endif //!_INC_DIBAPI Với khuôn khổ giáo trình, chúng tơi khơng đưa nội dung tập tin cài đặt Tuy nhiên chúng tơi giải thích ngắn gọn hàm Các cài đặt cụ thể xin bạn xem project MFCExample ñĩa CD Tập tin MyFile.cpp cài ñặt hàm ñọc ghi tập tin ảnh dạng bmp Hàm ñọc tập tin ảnh ReadDIBFile ñọc nội dung tập tin file trả danh (handle) HDIB ñối tượng ảnh DIB thành công Ngược lại, giá trị trả NULL Trong ứng dụng chúng ta, người dùng chọn menu File Open mở ñọc tập tin, ta gọi hàm ñể ñọc nội dung ảnh Hàm ñược dùng cài ñặt mở tập tin ảnh lớp CMFCExampleDoc HDIB WINAPI ReadDIBFile(CFile& file); Hàm lưu tập tin ảnh SaveDIB lưu nội dung ảnh HDIB vào tập tin file Nếu thành công giá trị trả TRUE, ngược lại, FALSE Trong ứng dụng chúng ta, người dùng chọn lưu tập tin (File Save), ta gọi hàm ñể lưu nội dung ảnh BOOL WINAPI SaveDIB(HDIB hDib, CFile& file); Tập tin DIBAPI.cpp cài ñặt số hàm thao tác liệu ảnh Hàm PaintDIB vẽ ảnh bitmap hDIB với kích thước lpDIBRect lên vùng hình chữ nhật lpDCRect Device Context hDC Dữ liệu bảng màu ảnh hDIB ñược xác ñịnh pPal Nếu ảnh ñược vẽ, giá trị trả TRUE, ngược lại FALSE BOOL WINAPI PaintDIB(HDC hDC, LPRECT lpDCRect, HDIB hDIB, LPRECT lpDIBRect, CPalette* pPal); Hàm CreateDIBPalette tạo bảng màu cho ảnh hDIB Bảng màu ảnh hDIB cần tạo ñược 134 gởi qua trỏ pPal Nếu thành công hàm trả giá trị TRUE, ngược lại FALSE BOOL WINAPI CreateDIBPalette(HDIB hDIB, CPalette* pPal); Hàm FindDIBBits lấy ñịa vùng nhớ liệu ảnh LPSTR WINAPI FindDIBBits(LPSTR lpbi); ðối với ñối tượng ảnh, liệu khối nhớ cấp phát tồn cục Windows (xem lại hàm ReadDIBFile) Mặt khác, ta lại biết liệu ảnh bitmap ñược tổ chức theo cấu trúc phức tạp gồm hai phần Header Data Vì thế, muốn thao tác đến xác liệu ta phải "ép" (cast) vùng nhớ tương ứng cấu trúc liệu mà ta cần ðối với hàm FindDIBBits hàm tiếp theo, thực hành hiểu rõ cách thao tác ñể có dự liệu mong muốn Hàm FindDIBBits có mục đích lấy ñược vùng liệu ảnh Các giải thuật ảnh mà thao tác sau thao tác vùng liệu ảnh Hàm ñơn giản trả ñịa vùng liệu ảnh dạng mảng byte ảnh Khi thao tác ảnh 256 màu, ñiểm ảnh ảnh thật byte mảng sau tham chiếu giá trị màu bảng màu ảnh Tương tự, hàm DIBWidth DIBHeight lấy chiều rộng chiều cao ảnh Thơng qua trỏ trỏ đến vùng nhớ ảnh lpDIB ñịnh nghĩa cấu trúc BITMAPINFOHEADER ảnh bitmap Windows, ta dễ dàng xác ñịnh chiều rộng chiều cao ảnh DWORD WINAPI DIBWidth(LPSTR lpDIB); DWORD WINAPI DIBHeight(LPSTR lpDIB); Vì kích thước bảng màu ảnh bitmap họ Windows 3.0 khác loại ảnh DIB cịn lại, ta dùng hàm PaletteSize để lấy xác kích thước palette ảnh WORD WINAPI PaletteSize(LPSTR lpbi); Thơng qua giá trị biBitCount cấu trúc BITMAPINFOHEADER ta biết ñược ảnh 2, 16, 256 hay true color, ta dùng hàm DIBNumColors ñể xác ñịnh số lượng màu ảnh bitmap WORD WINAPI DIBNumColors (LPSTR lpbi); Cuối cùng, hàm CopyHandle copy ñối tượng DIB ñể tạo ñối tượng vùng nhớ có liệu giống vùng nhớ khác Hàm dùng với mục đích tạo lại đối tượng DIB thơng qua danh cần thiết HGLOBAL WINAPI CopyHandle (HGLOBAL h); 6.3.2 ðọc hiển thị tập tin ảnh bmp ứng dụng ðể quản lý ñối tượng ảnh, cần tạo lập ñối tượng liệu lớp CMFCExampleDoc Chúng ta cần đối tượng ảnh HDIB m_hDIB, xác định thơng qua kích 135 thước CSize m_sizeDoc, có bảng màu CPalette* m_palDIB, số màu ảnh DWORD m_NumColors Các biến ñược ñịnh nghĩa tập tin CMFCExampleDoc.h 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 // MFCExampleDoc.h : interface of the CMFCExampleDoc class // ///////////////////////////////////////////////////////////////////////////// #if !defined(AFX_MFCEXAMPLEDOC_H INCLUDED_) #define AFX_MFCEXAMPLEDOC_H INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include"DIBAPI.h" class CMFCExampleDoc : public CDocument { protected: // create from serialization only CMFCExampleDoc(); DECLARE_DYNCREATE(CMFCExampleDoc) // Attributes public: HDIB GetHDIB() const { return m_hDIB; } CPalette* GetDocPalette() const { return m_palDIB; } CSize GetDocSize() const { return m_sizeDoc; } // Operations public: void ReplaceHDIB(HDIB hDIB); void InitDIBData(); // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CMFCExampleDoc) public: virtual BOOL OnNewDocument(); virtual void Serialize(CArchive& ar); virtual BOOL OnOpenDocument(LPCTSTR lpszPathName); virtual BOOL OnSaveDocument(LPCTSTR lpszPathName); //}}AFX_VIRTUAL // Implementation public: DWORD m_NumColors; BOOL m_bModified; virtual ~CMFCExampleDoc(); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif protected: HDIB m_hDIB; CPalette* m_palDIB; CSize m_sizeDoc; // Generated message map functions protected: //{{AFX_MSG(CMFCExampleDoc) 136 63 64 65 66 67 68 69 70 71 72 73 74 75 // NOTE - the ClassWizard will add and remove member functions here // DO NOT EDIT what you see in these blocks of generated code ! //}}AFX_MSG DECLARE_MESSAGE_MAP() }; ///////////////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately // before the previous line #endif // !defined(AFX_MFCEXAMPLEDOC_H INCLUDED_) Trong tập tin trên, ta có số hàm thao tác tập tin liệu thông tin ảnh, hàm ñược cài ñặt tập tin CMFCExampleDoc.cpp ðể ý hàm OnOpenDocument, OnSaveDocument ñược tạo lập nhờ ClassWizard 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 // MFCExampleDoc.cpp : implementation of the CMFCExampleDoc class // #include "stdafx.h" #include "MFCExample.h" #include "MFCExampleDoc.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = FILE ; #endif ///////////////////////////////////////////////////////////////////////////// // CMFCExampleDoc IMPLEMENT_DYNCREATE(CMFCExampleDoc, CDocument) BEGIN_MESSAGE_MAP(CMFCExampleDoc, CDocument) //{{AFX_MSG_MAP(CMFCExampleDoc) // NOTE - the ClassWizard will add and remove mapping macros here // DO NOT EDIT what you see in these blocks of generated code! //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CMFCExampleDoc construction/destruction CMFCExampleDoc::CMFCExampleDoc() { m_hDIB = NULL; m_palDIB = NULL; m_sizeDoc = CSize(1,1); // dummy value to make CScrollView happy } CMFCExampleDoc::~CMFCExampleDoc() { if (m_hDIB != NULL) { ::GlobalFree((HGLOBAL) m_hDIB); } if (m_palDIB != NULL) { delete m_palDIB; } 137 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 } BOOL CMFCExampleDoc::OnNewDocument() { if (!CDocument::OnNewDocument()) return FALSE; if (m_hDIB != NULL) { ::GlobalFree((HGLOBAL) m_hDIB); } if (m_palDIB != NULL) { delete m_palDIB; } m_hDIB = NULL; m_palDIB = NULL; m_NumColors = 0; m_sizeDoc = CSize(1,1); // dummy value to make CScrollView happy return TRUE; } ///////////////////////////////////////////////////////////////////////////// // CMFCExampleDoc serialization void CMFCExampleDoc::Serialize(CArchive& ar) { if (ar.IsStoring()) { // TODO: add storing code here } else { // TODO: add loading code here } } ///////////////////////////////////////////////////////////////////////////// // CMFCExampleDoc diagnostics #ifdef _DEBUG void CMFCExampleDoc::AssertValid() const { CDocument::AssertValid(); } void CMFCExampleDoc::Dump(CDumpContext& dc) const { CDocument::Dump(dc); } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CMFCExampleDoc commands BOOL CMFCExampleDoc::OnOpenDocument(LPCTSTR lpszPathName) { CFile file; CFileException fe; if (!file.Open(lpszPathName, CFile::modeRead | CFile::shareDenyWrite, &fe)) { ReportSaveLoadException(lpszPathName, &fe, FALSE, AFX_IDP_FAILED_TO_OPEN_DOC); return FALSE; } DeleteContents(); 138 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 BeginWaitCursor(); // replace calls to Serialize with ReadDIBFile function TRY { m_hDIB = ::ReadDIBFile(file); } CATCH (CFileException, eLoad) { file.Abort(); // will not throw an exception EndWaitCursor(); ReportSaveLoadException(lpszPathName, eLoad, FALSE, AFX_IDP_FAILED_TO_OPEN_DOC); m_hDIB = NULL; return FALSE; } END_CATCH InitDIBData(); EndWaitCursor(); if (m_hDIB == NULL) { // may not be DIB format MessageBox(NULL, "Can not read selected file.\nThis is not valid bitmap file, or its format is not currently supported.", NULL, MB_ICONEXCLAMATION|MB_OK); return FALSE; } SetPathName(lpszPathName); SetModifiedFlag(FALSE); // start off with unmodified return TRUE; } BOOL CMFCExampleDoc::OnSaveDocument(LPCTSTR lpszPathName) { CFile file; CFileException fe; if (!file.Open(lpszPathName, CFile::modeCreate | CFile::modeReadWrite | CFile::shareExclusive, &fe)) { ReportSaveLoadException(lpszPathName, &fe, TRUE, AFX_IDP_INVALID_FILENAME); return FALSE; } // replace calls to Serialize with SaveDIB function BOOL bSuccess = FALSE; TRY { BeginWaitCursor(); bSuccess = ::SaveDIB(m_hDIB, file); file.Close(); } CATCH (CException, eSave) { file.Abort(); // will not throw an exception EndWaitCursor(); ReportSaveLoadException(lpszPathName, eSave, TRUE, AFX_IDP_FAILED_TO_SAVE_DOC); return FALSE; } END_CATCH EndWaitCursor(); SetModifiedFlag(FALSE); // back to unmodified 139 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 m_bModified = FALSE; if (!bSuccess) { // may be other-style DIB (load supported but not save) // or other problem in SaveDIB MessageBox(NULL, "Can not save current bitmap Check file pathname again!", NULL, MB_ICONEXCLAMATION | MB_OK); } return bSuccess; } void CMFCExampleDoc::InitDIBData() { if (m_palDIB != NULL) { delete m_palDIB; m_palDIB = NULL; } if (m_hDIB == NULL) { return; } // Set up document size LPSTR lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) m_hDIB); if (::DIBWidth(lpDIB) > INT_MAX ||::DIBHeight(lpDIB) > INT_MAX) { ::GlobalUnlock((HGLOBAL) m_hDIB); ::GlobalFree((HGLOBAL) m_hDIB); m_hDIB = NULL; MessageBox(NULL, "Bitmap too big!", NULL, MB_ICONEXCLAMATION | MB_OK); return; } m_NumColors = ::DIBNumColors(lpDIB); m_sizeDoc = CSize((int) ::DIBWidth(lpDIB), (int) ::DIBHeight(lpDIB)); ::GlobalUnlock((HGLOBAL) m_hDIB); // Create copy of palette m_palDIB = new CPalette; if (m_palDIB == NULL) { // we must be really low on memory ::GlobalFree((HGLOBAL) m_hDIB); m_hDIB = NULL; return; } if (::CreateDIBPalette(m_hDIB, m_palDIB) == NULL) { // DIB may not have a palette delete m_palDIB; m_palDIB = NULL; return; } } void CMFCExampleDoc::ReplaceHDIB(HDIB hDIB) { if (m_hDIB != NULL) { ::GlobalFree((HGLOBAL) m_hDIB); } m_hDIB = hDIB; } Với tập tin ảnh ñã ñược nạp vào biến m_hDIB lớp CMFCExampleDoc, ta việc dùng 140 hàm OnDraw lớp CMFCExampleView ñể xuất lên cửa sổ ứng dụng Ngồi ta chặn thơng điệp WM_KEYDOWN ứng hàm OnKeyDown ñể thao tác scroll ảnh phím Nội dung tập tin CMFCExampleView.h sau: 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 // MFCExampleView.h : interface of the CMFCExampleView class // ///////////////////////////////////////////////////////////////////////////// #if !defined(AFX_MFCEXAMPLEVIEW_H INCLUDED_) #define AFX_MFCEXAMPLEVIEW_H INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 class CMFCExampleView : public CScrollView { protected: // create from serialization only CMFCExampleView(); DECLARE_DYNCREATE(CMFCExampleView) // Attributes public: CMFCExampleDoc* GetDocument(); // Operations public: // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CMFCExampleView) public: virtual void OnDraw(CDC* pDC); // overridden to draw this view virtual BOOL PreCreateWindow(CREATESTRUCT& cs); protected: virtual void OnInitialUpdate(); // called first time after construct virtual BOOL OnPreparePrinting(CPrintInfo* pInfo); virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo); virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo); //}}AFX_VIRTUAL // Implementation public: virtual ~CMFCExampleView(); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif protected: // Generated message map functions protected: //{{AFX_MSG(CMFCExampleView) afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; #ifndef _DEBUG // debug version in MFCExampleView.cpp inline CMFCExampleDoc* CMFCExampleView::GetDocument() { return (CMFCExampleDoc*)m_pDocument; } #endif 141 61 62 63 64 65 66 67 68 ///////////////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line #endif // !defined(AFX_MFCEXAMPLEVIEW_H INCLUDED_) Sau cài ñặt lại hàm OnDraw, OnInitialUpdate hàm OnKeyDown, thao tác mở tập tin ảnh bitmap Elephant.bmp, ta có kết hình 6.7 Hình 6.7 Hiển thị ảnh Elephant.bmp ứng dụng MFCExample Nội dung tập tin CMFCExampleView.cpp: 10 11 12 13 14 15 16 17 // MFCExampleView.cpp : implementation of the CMFCExampleView class // #include "stdafx.h" #include "MFCExample.h" #include "MFCExampleDoc.h" #include "MFCExampleView.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = FILE ; #endif ///////////////////////////////////////////////////////////////////////////// // CMFCExampleView 142 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 IMPLEMENT_DYNCREATE(CMFCExampleView, CScrollView) BEGIN_MESSAGE_MAP(CMFCExampleView, CScrollView) //{{AFX_MSG_MAP(CMFCExampleView) ON_WM_KEYDOWN() //}}AFX_MSG_MAP // Standard printing commands ON_COMMAND(ID_FILE_PRINT, CScrollView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, CScrollView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, CScrollView::OnFilePrintPreview) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CMFCExampleView construction/destruction CMFCExampleView::CMFCExampleView() { // TODO: add construction code here } CMFCExampleView::~CMFCExampleView() { } BOOL CMFCExampleView::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs return CScrollView::PreCreateWindow(cs); } ///////////////////////////////////////////////////////////////////////////// // CMFCExampleView drawing void CMFCExampleView::OnDraw(CDC* pDC) { CMFCExampleDoc* pDoc = GetDocument(); HDIB hDIB = pDoc->GetHDIB(); if (hDIB != NULL) { LPSTR lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB); int cxDIB = (int) ::DIBWidth(lpDIB); // Size of DIB - x int cyDIB = (int) ::DIBHeight(lpDIB); // Size of DIB - y ::GlobalUnlock((HGLOBAL) hDIB); CRect rCDIP; rCDIP.top = rCDIP.left = 0; rCDIP.right = cxDIB; rCDIP.bottom = cyDIB; CRect rcDest; if (pDC->IsPrinting()) // printer DC { // get size of printer page (in pixels) int cxPage = pDC->GetDeviceCaps(HORZRES); int cyPage = pDC->GetDeviceCaps(VERTRES); // get printer pixels per inch int cxInch = pDC->GetDeviceCaps(LOGPIXELSX); int cyInch = pDC->GetDeviceCaps(LOGPIXELSY); // // Best Fit case create a rectangle which preserves // the DIB's aspect ratio, and fills the page horizontally // // The formula in the "->bottom" field below calculates the Y 143 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 // position of the printed bitmap, based on the size of the // bitmap, the width of the page, and the relative size of // a printed pixel (cyInch / cxInch) // rcDest.top = rcDest.left = 0; rcDest.bottom = (int)(((double)cyDIB * cxPage * cyInch) / ((double)cxDIB * cxInch)); rcDest.right = cxPage; } else // not printer DC rcDest = rCDIP; ::PaintDIB(pDC->m_hDC, &rcDest, pDoc->GetHDIB(), &rCDIP, pDoc->GetDocPalette()); } } void CMFCExampleView::OnInitialUpdate() { CScrollView::OnInitialUpdate(); ASSERT(GetDocument() != NULL); SetScrollSizes(MM_TEXT, GetDocument()->GetDocSize()); } ///////////////////////////////////////////////////////////////////////////// // CMFCExampleView printing BOOL CMFCExampleView::OnPreparePrinting(CPrintInfo* pInfo) { // default preparation return DoPreparePrinting(pInfo); } void CMFCExampleView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add extra initialization before printing } void CMFCExampleView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add cleanup after printing } ///////////////////////////////////////////////////////////////////////////// // CMFCExampleView diagnostics #ifdef _DEBUG void CMFCExampleView::AssertValid() const { CScrollView::AssertValid(); } void CMFCExampleView::Dump(CDumpContext& dc) const { CScrollView::Dump(dc); } CMFCExampleDoc* CMFCExampleView::GetDocument() // non-debug version is inline { ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMFCExampleDoc))); return (CMFCExampleDoc*)m_pDocument; } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CMFCExampleView message handlers 144 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 void CMFCExampleView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { switch(nChar) { case VK_HOME: OnVScroll(SB_TOP, 0, NULL); OnHScroll(SB_LEFT, 0, NULL); break; case VK_END: OnVScroll(SB_BOTTOM, 0, NULL); OnHScroll(SB_RIGHT, 0, NULL); break; case VK_UP: OnVScroll(SB_LINEUP, 0, NULL); break; case VK_DOWN: OnVScroll(SB_LINEDOWN, 0, NULL); break; case VK_PRIOR: OnVScroll(SB_PAGEUP, 0, NULL); break; case VK_NEXT: OnVScroll(SB_PAGEDOWN, 0, NULL); break; case VK_LEFT: OnHScroll(SB_LINELEFT, 0, NULL); break; case VK_RIGHT: OnHScroll(SB_LINERIGHT, 0, NULL); break; default: CScrollView::OnKeyDown(nChar, nRepCnt, nFlags); } } 6.4 THAY LỜI KẾT Qua học này, ñã nắm ñược chế xây dựng ứng dụng MFC Windows Với quản lý chặt chẽ Application Framework – xem phần 6.1 – hỗ trợ trực quan công cụ ClassWizard – xem phần 6.2, dễ dàng lập trình thao tác xử lý cho ứng dụng Bằng việc tìm hiểu lớp CDocument CView – xem phần 6.3, ñã bước ñầu quản lý ñược liệu thể ñược giao diện ứng dụng dạng SDI Và thế, hiểu MFC sử dụng để lập trình cách lập trình trực tiếp với hàm API Win32 Application, ñồng thời hiểu học lập trình Windows cần học thông qua minh họa với Win32 Application trước Từ đây, bạn dễ dàng tìm hiểu kỹ lớp ñối tượng MFC MSDN, vấn ñề mở rộng khác ñể phát triển khả lập trình xây dựng ứng dụng phức tạp chuyên nghiệp Windows 145 TÀI LIỆU THAM KHẢO Programming Windows, Fifth Edition – Charles Petzold – Microsoft Press 1999 Programming Microsoft Visual C++, Fifth Edition – David J Kruglinski, George Shepherd, and Scot Wingo – Microsoft Press 1998 Giáo trình Lập trình C Windows – Nguyễn Hà Giang, Mai Xn Hùng, Hồng Ngọc Bảo Quốc, Nguyễn ðình Quyền – ðại học Quốc gia Tp Hồ Chí Minh 2002 Microsoft Development Network Library – http://msdn.microsoft.com 146 ... ñổi thu? ?c tính màu s? ?c văn c? ??n xuất DC COLORREF SetTextColor(HDC hdc, COLORREF crColor); Với thao t? ?c trên, ta c? ? đoạn code hàm WndProc ứng dụng VanBan tập tin VanBan.cpp sau (c? ?c phần kh? ?c tập... ñư? ?c click trư? ?c tới ñiểm vừa ñư? ?c click Quy trình th? ?c cho ñến người dùng click chuột phải, l? ?c ta vẽ từ điểm ña gi? ?c ñến ñiểm vừa ñư? ?c click chuột phải ñể hồn thành đa gi? ?c Ngồi ra, ứng dụng c? ??n... tập tin MFCExample.cpp 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 // MFCExample.cpp : Defines the class behaviors for the application // #include "stdafx.h" #include "MFCExample.h"