Nếu việc trang trí gồm nhiều thao tác phức tạp thì nên thực hiện chúng trên DC ảo, sau đó chuyển kết quả ra DC hiển thị. Chỉ một lần duy nhất cho mỗi nội dung trang trí, như thế sẽ cải thiện đáng kể chất lượng đồ họa.
Ứng với mỗi DC ảo tạo ra trong bộ nhớ, ngoài đối tượng CDC quản lý, ta cần sự phối hợp của đối tượng bitmap làm nền thay thế đối tượng bitmap tượng trưng không sử dụng được mà hệ thống gán cho DC khi tạo lập. Bố cục xử lý của hành vi OnPaint có sử dụng đối tượng DC ảo như sau:
CClientDC dc(this); // Đối tượng DC hiển thị RECT rect;
CDC memDrawDC; // Đối tượng DC ảo để vẽ trung gian CBitmap memDrawBmp;
CBitmap *memDrawOldBmp; GetClientRect ( &rt );
int CX = rect.right–rect.left ; int CY = rect.bottom–rect.top; memDrawBmp.CreateCompatibleBitmap( &dc, CX, CY );
memDrawDC.CreateCompatibleDC( &dc );
memDrawOldBmp = memDrawDC.SelectObject( &memDrawBmp );
... // Trang trí memDrawDC // Chuyển nội dung DC ảo sang dc:
dc.StretchBlt ( 0, 0, CX,CY, &memDrawDC, CX,CY, SRCCOPY ); // Hủy bỏ các đối tượng GDI:
memDrawDC.SelectObject(&memDrawOldBmp); memDrawBmp.DeleteObject();
memDrawDC.DeleteDC();
2 Phần tiếp theo ta thực hiện ứng dụng tương tự VD08, đồng thời tạo dòng chữ chạy theo kiểu bảng chữ điện tử trong vùng client của cửa sổ chính.
Tạo dự án VD09 tương tự dự án VD08.
Xử lý Trang trí memDrawDC trong OnPaint của CEmpWnd như sau: BITMAP bmpInfo;
m_myPict.GetBitmap( &bmpInfo );
memDrawDC.StretchBlt( 0, 0, CX, CY, &memDC,
0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight,
SRCCOPY );
memDrawDC.SetTextColor( RGB(255,0,0) ); // text color memDrawDC.SetBkMode( TRANSPARENT ); // transparent memDrawDC.TextOut( 30, 100, Chuỗi, I );
Xem VD09.
Ứng dụng công cụ GDI 65
Với các đối tượng GDI được sử dụng thường xuyên thì việc lặp đi lặp lại các thao tác tạo và hủy bỏ chúng trong các hành vi trang trí của CEmpWnd sẽ làm lãng phí tài nguyên của hệ thống. Nên chuyển tất cả các thao tác đó về hai hành vi OnCreate và OnDestroy của CEmpWnd một cách phù hợp.
Bạn hãy thử áp dụng điều lưu ý này cho VD09. 6.5 ẢNH CHUYỂN ĐỘNG TRONG VÙNG CLIENT:
Được thực hiện một cách đơn giản bằng kỹ thuật hoạt hình. Ta chuẩn bị một số ảnh cơ bản của chuỗi hoạt động đó, sau đó thực hiện hiển thị và tráo ảnh theo trình tự với khoảng thời gian chờ hợp lý.
Các ảnh trong nội dung hoạt hình được quản lý bởi công cụ GDI thích hợp:
CBitmap: Mỗi bitmap quản lý được một ảnh. Ta dùng nhiều bitmap. Ảnh vẽ bằng hành vi DrawState của đối tượng DC quản lý thiết bị hiển thị. Kích thước ảnh hiển thị không thay đổi.
CDC: Lồng tất cả các ảnh vào một DC. Từ DC này ta có thể chép bất kỳ phần ảnh cần vẽ nào sang DC hiển thị. Có thể thay đổi kích thước ảnh tùy ý: StretchBlt.
CImageList: Lớp đối tượng quản lý tập hợp nhiều ảnh có cùng kích thước. Khả năng thao tác trên danh sách ảnh của CImageList là rất tốt.
2 Trong phần này ta xây dựng ứng dụng với hình ảnh chú bướm bay trong vùng client của cửa sổ. Tập tin butterfly.bmp trong thư mục BMP chứa các ảnh chuyển động của bướm. Ta dùng cách thứ 2, lồng các ảnh vào DC và vẽ lên DC hiển thị. Các bước thực hiện dự án như sau:
Tạo dự án VD10 tương tự dự án VD09.
Bổ sung bitmap resource với số hiệu IDB_ANIMATION mà nội dung được lấy từ tập tin chứa các ảnh hoạt hình. Ghi nhớ số ảnh trong bitmap đó. Chẳng hạn, chọn tập tin butterfly.bmp trong thư mục BMP. Tập tin này có 4 ảnh, kích thước 32x28.
Bổ sung các đối tượng thuộc tính protected cho lớp CEmpWnd: - m_butterDC : Đối tượng CDC, quản lý DC lồng ảnh.
- m_butterBmp : Đối tượng CBitmap, quản lý các ảnh hoạt hình. - m_butterOldBmp : Đối tượng CBitmap*, quản lý con trỏ chỉ đến
đối tượng bitmap cũ của m_butterDC.
- m_pictNo : Kiểu int, quản lý số thứ tự của hình đang được hiển thị trong các ảnh hoạt hình nói trên.
Hành vi OnCreate của CEmpWnd thực hiện các chuẩn bị:
66 Lập trình Windows với MFC - Microsoft Visual C++ 6.0 - Lê Ngọc Thạnh - lntmail@yahoo.com{ {
if (CWnd::OnCreate(lpCreateStruct) == -1) return -1;
// TODO: Add your specialized creation code here SetTimer( IDD_TIMER, 250, NULL );
m_myPict.LoadBitmap( IDB_MYPICT ); // Animation objects by EX10
m_butterBmp.LoadBitmap( IDB_ANIMATION ); m_butterDC.CreateCompatibleDC( NULL );
m_butterOldBmp = butterDC.SelectObject( &m_butterBmp ); m_pictNo = 0;
return 0; }
Hành vi OnPaint vẽ hình và tự tăng vị trí chọn hình cho lần vẽ sau đó: memDrawDC.StretchBlt( 20, 50, 32, 28, &m_butterDC,
m_pictNo*32 , 0 , 32 , 28 , SRCCOPY ); m_pictNo++; // Chọn ảnh kế tiếp
if (m_pictNo >= 4) m_pictNo = 0;
Hành vi OnDestroy hủy bỏ các thuộc tính GDI: m_butterDC.SelectObject(m_butterOldBmp); m_butterBmp.DeleteObject();
m_butterDC.DeleteDC();
Nhận xét: Phần nền của ảnh hoạt hình che khuất ảnh nền. Để khắc phục ta sử dụng một ảnh bitmap làm mặt nạ cho ảnh hoạt hình để ấn định phần nội dung được vẽ trên ảnh hoạt hình.
) Hành vi MaskBlt của CDC cho phép dùng monochrome bitmap làm lưới lọc ảnh điểm phần nổi của ảnh khi chép ảnh từ DC nguồn lên DC đích (95/98/Me unsupported). Bạn hãy thử thực hiện với VD10 như bài tập. 6.6 CImageList - CÔNG CỤ QUẢN LÝ BỘ ẢNH CÙNG CỠ:
Xây dựng dự án VD11 trên cơ sở cải tiến VD10; bộ ảnh hoạt hình sẽ được quản lý bởi đối tượng CImageList:
Tạo dự án VD11 tương tự dự án VD10.
Bổ sung đối tượng thuộc tính m_butterImg kiểu CImageList làm nhiệm vụ quản lý các ảnh. Xóa các thuộc tính m_butterBmp, m_butterDC và m_butterOldBmp vì không còn cần thiết.
Ứng dụng công cụ GDI 67
Hành vi OnCreate của CEmpWnd thực hiện các chuẩn bị như sau: int CEmpWnd::OnCreate( LPCREATESTRUCT lpCreateStruct ) {
if (CWnd::OnCreate(lpCreateStruct) == -1) return -1;
// TODO: Add your specialized creation code here SetTimer(IDD_TIMER, 250, NULL);
m_mypict.LoadBitmap(IDB_MYPICT); // animation object by EX10
m_butterImg.Create(IDB_ANIMATION,32,4,RGB(255,255,255)); m_pictNo = 0;
return 0; }
Hành vi OnPaint sử dụng hành vi Draw của m_butterImg vẽ ảnh: m_butterImg.Draw( &memDrawDC, m_pictNo, CPoint(30, 170), ILD_NORMAL);
m_pictNo++;
if (m_pictNo >= 4) m_pictNo = 0;
Hành vi OnDestroy hủy bỏ đối tượng CImageList: m_butterImg.DeleteImageList();
6.7 CRgn – CỬA SỔ CÓ HÌNH DẠNG TÙY Ý:
Khuôn dạng của region có thể dùng làm khuôn dạng của cửa sổ thông qua hành vi SetWindowRgn của đối tượng cửa sổ. Phần sau đây minh họa cho vấn đề trên và được cài đặt trong hành vi OnCreate của cửa sổ (VD12).
CRgn newShape;
newShape.CreateEllipticRgn( 0, 0, 200, 100 ); SetWindowRgn( newShape, TRUE );
THỰC HÀNH:
1. Viết ứng dụng với cửa sổ giao diện chính có hình tam giác.
2. Viết ứng dụng với cửa sổ giao diện chính có hình ngôi sao năm cánh. 3. Viết ứng dụng hiển thị nội dung của nhiều ảnh theo thứ tự luân phiên. Sự chuyển tiếp giữa hai ảnh bất kỳ được thực hiện bằng kỹ thuật pha trộn ảnh. 4. Viết ứng dụng hiển thị ảnh cuộn (scroll) từ trái sang phải.