Các kỹ thuật của Visual C++ được khai thác
Trang 1B CÁC KỸ THUẬT CỦA VISUAL C++ ĐƯỢC KHAI THÁC
v Chương trình được viết trên môi trường Window bằng Visual C++
v Đề tài chương trình được tạo bởi MFC AppWizard(exe) dựa trên Dialog-Based
v Khi tạo Dialog_Based sẽ không có các chức năng như Menu, Toolbar và Status bar vì các lớp ứng dụng của Dialog-Based không có các chức năng này Sau khi AppWizard ta thấy có 3 lớp được tạo ra :
Ø CAboutDlg : Lớp Dialog liên quan tới Aboutbox Ø COngdauApp : lớp CWinApp dùng cho trọn ứng dụng
Ø COngdauDlg : lớp CDialog dùng cho trọn ứng dụng
v Lớp CObject(): (2)
Ø Lớp CObject chứa những chức năng cơ bản của lớp MFC CObject chứ những hàm thành viên hổ trợ cho việc cấp phát động ,yêu cầu sản sinh hàng loạt (serialization), gán đối tượng và nhậ diện động đối tượng vào lúc chạy chương trình
v Lớp CCmdTarget():
Ø Lớp CCmdTarget này viết tắt chữ Class Command Target được dẫn
xuất từ CObject Những lớp nào cần tiếp xúc với User và với hệ
điều hành thông qua các thông điệp và lệnh thì sẽ được thông qua
lớp CCmdTarget
Ø Lớp CCmdTarget được xem như là lớp cơ sở liên quan đến cơ chế message-map của MFC Message-map sẽ hướng dẫn đường đi cho các command(lệnh) hoặc message Theo định nghĩa người ta phân biệt 1 command là 1 thông điệp xuất phát từ 1 mục chọn trình đơn, 1 nút điều khiển hoặc phím tắt , còn lại là thông điệp Lớp nào dẫn xuất từ lớp CCmdTarget đều có riêng 1 message map Cho phép mỗi lớp giải quyết những message liên quan đến phần quyền của mình, để cho những thông điệp khác giải quyết bởi các lớp cấp cao
ở trên v Lớp CWnd():
Ø Lớp CWnd(class window) là lớp thừa kế của lớp CcmdTarget là 1
lớp khá quan trọng, cung cấp những chức năng cơ bản cho tất cả các lớp cửa sổ,như các ô điều khiển(đây là 1 loại cửa sổ),các khung đối thoại và view Chỉ có những lớp dẫn xuất từ CWnd mới có thể nhận
được những thông điệp
Trang 2v CButton():
Ø CButton dược dẫn xuất từ lớp CWnd , cung cấp những chức năng cơ
bản của các nút điều khiển windows, nút điều khiền là1 cửa sổ con cái nhỏ hình chữ nhật mà ta có thể bấm tắt cho ON hoặc OFF Nút điều khiển có thể được sử dụng 1 mình hoặc 1 nhóm và có thể mang
nhãn hoặc không
Ø Các nút điều khiển điển hình là1 ô duyệt(check box), nút đài(radio button),và nút ấn (pushbutton)
I Lớp CWinApp:
v COngdauApp kế thừa lớp CWinApp
v CwinApp viết tắt chữ Class Window Application theo sơ đồ dẫn xuất dưới đây:
Ø CwinApp quản lý những công việc được đòi hỏi để khởi động ứng dụng và mọi thể hiện của ứng dụng cũng như cũng như để chạy và kết thúc ứng dụng MFC Lớp CWinApp được xem là lớp ứng dụng cốt lõi của MFC.Ví dụ ở đây COngdauApp là giao diện lo “việc đối ngoại” với Window khi một tình huống nào đó xảy ra trong Window thì một thông điệp sẽ được gởi đến cho chương trình (COngdauApp) để cho nó biết được cái gì đang xảy ra
Ø Ví dụ : 1 phím được ấn xuống thì thông điệp WM_KEYDOWN sẽ được phát ra và chuyển cho COngdauApp và đến phiên chương trình sẽ khởi động hàm giải quyết vấn đề này là OnKeyDown( )
Ø SDI và MDI đi trước lớp này phủ quyết(override) hàm InitInstace( ), hàm này khai báo 1 phủ quyết instance của lớp COngdauDlg thông qua lệnh :
Trang 3COngdauDlg dlg;
Rồi gọi hàm DoModal( ) để cho hiển thị khung đối thoại lên màn hình rồi trả về IDOK nếu người sử dụng ấn nút OK hoặc trả về IDCANCEL nếu ấn nút CANCEL
Ø Hàm InitInstace trả về FALSE (nghĩa là mọi phần khởi gán tạm ổn,cho chạy
phần ứng dụng ) vì đây là 1 ứng dụng Dialog_Based và khung đối thoại bị đóng lại thì ứng dụng mới chấm dứt
II Lớp CDialog :
v COngdauDlg kế thừa lớp CDialog
v CDialog viết tắt chữ class Dialog theo dẫn xuất từ các lớp dưới đây :
v Lớp CDialog là dẫn xuất từ lớp CWnd là lớp cơ sở được dùng để hiển thị khung đối thoại lên màn hình.Thư viện MFC cung cấp những lớp Dialog để hổ trợ những khung đối thoại thông dụng được cài sẵn (gọi là common Dialog) Có nhiều loại khung đối thoại, mỗi loại khung đối thoại được dùng cho mỗi mục đích khác nhau Có các loại khung đối thoại sau:
II.1 Message box : khung thông báo dùng để hiển thi thông tin cho người
sử dụng biết.Ta có thể gọi nó như sau :
Trang 4LPCTSTR lptzText // con trỏ chỉ về phần văn bản LPCTSTR lpszCaption // con trỏ chỉ về phần tựa đề UINT nType // kiểu message box
Ø MFC:
(1) int AfxMessageBox(LPCTSTR lptzText,UINT nType=MB_OK,
UINT nIDHelp=0);
Dòng lệnh này sẽ tạo 1 message box với dấu chấm than(!)trong 1 hình tam giác vàng
(2) int AFXAPI AfxMessage(UINT nIDPrompt, UINT nType=MB_OK, UINT nIDHelp=(UINT)-1); Ø Ý nghĩa các thông số như sau:
_ lpszText : con trỏ chỉ về 1 đối tượng Cstring hoặc chuỗi null-terminated chứa thông báo cần được hiển thị lên ô thông báo
_ nType : kiểu cách trình bày ô message box
_ nIDHelp : Mã cảnh ứng help đối với thông báo; trị zero cho biết sẽ sử dụng Help-context mặc nhiên của ứng dụng _ nIDPrompt : mã nhận điện ID duy nhất dùng để qui chiếu về 1 chuỗi trong string table
II.2 Modal Dialog Box :Khung đối thoại này là phổ biến nhất Khi khung
đối thoại này khởi động,thì người sử dụng chỉ được phép nhập liệu mà thôi, và phần còn lại ứng dụng sẽ bị khoá chặt không cho nhận thông điệp cho tơiù khi khung đối thoại chấm dứt và biến mất.Với khung này người sử dụng phải làm cho xong việc rồi đóng lại thì mới qua khung đối thoại khác làm việc Trước khi thêm khung đối thoại này vào ứng dụng ta phải tạo chúng.Developer Studio đã đưa vào 1 trình đơn gọi là dialogbox editor thuộc nhóm resource editor giúp ta xây dựng 1 dialog resource.Sau đó class Wizard sẽ giúp ta tạo dialog class
Ta triệu gọi hàm thành viên DoModal( ) của đối tượng
khung đối thoại để cho hiện lên màn hình
Trang 5II.3 Modeless dialog box:Khung đối thoại này xuất hiện và nằm lì trên màn
hình cho tới khi ta ra lệnh đóng lại.Trong khi khung đối thoại modeless nằm trên màn hình,người sử dụng có thể nhảy qua khung đối thoại khác làm việc rồi trở về khung modeless Khác với khung modal, khung đối thoại modeless cho phép ứng tiếp tục nhận và giải quyết thông điệp III Các tập tin cơ bản : (2)
v Như cách tạo trên ta có các tập tin sau:
Ø File.H : h viết tắt chữ header.tập tin tiêu đề chính đối với chương trình (ví
dụ ở đây là tập tin Ongdau.h) Nó thường chứa những ký hiệu toàn cục và
các chỉ thị #include đối với các tập tin h khác.Ngoài ra nó còn dẫn xuất lớp CongdauApp từ lớp CWndApp
Ø File.CPP : cpp viết tắt chữ C Plus Plus, nghĩa là C++.Đây là tập tin nguồn
còn gọi là tập tin “thiết đặt”(implementation file) của chương trình chính(ví dụ: Ongdau.cpp) Nó sẽ tạo 1 đối tượng thuộc lớp COngdauApp và phủ quyết hàm thành viên InitInstace( )
Ø File.RC và RESOURCE.H:
Ø RC viết tắt chữ Resource.File.rc là tập tin nguồn lực của dự án
Ø RESOURCE.H là tập tin tiêu đề nguồn lực Tập tin nguồn lực chứa những trình đơn mặc nhiên và accelerator, stringtables đối với chương trình MFC Nói chung nó tạo ra thư mục \RES chứa các tập tin icon, bitmap và cursor Ø FileDLG.H &fileDLG.CPP : DLG viết tắt chữ Dialog.Những tập tin này
tạo ra do ta tạo dựa trên Dialog-Based.Các tập tin này sẽ sẫn xuất và cài đặt lớp Dialog mang tên CfileDlg(Ví dụ :COngdauDlg),và cho bao gồm khung sườn nhữn g hàm thành viên dùng khởi gán khung đối thoại và thực hiện những trao đổi dữ liệu(data_exchange,DDX) giữa dialog với biến thành viên lớp
IV Các hàm có liên quan: (2) • Hàm OnCommand() :
v CWnd:: OnCommand()
v Virtual BOOL OnCommand(WPARAM wParam,LPARAM lParam) Ø Các thông số được giải thích như sau :
Trang 6_ wParam : Phần word low-order của thông số wParam cho biết mã ID nhận diện lệnh của mục chọn trình đơn hoặc của ô điều khiển Nếu thông điệp đến từ accelerator, thì high-order word sẽ bằng 1 Còn thông điệp đến từ 1 trình đơn thì high-order word sẽ bằng 0
_ lParam : Thông số này nhận diện ô điều khiển đã gởi đi thông điệp nếu thông điệp đến từ một ô điều khiển,bằng không là 0
Ø MFC sẽ cho gọi hàm này khi người sử dụng chọn 1 mục chọn trình đơn khi 1 ô điều khiển con gởi đi 1 thông tri(notification) hoặc khi 1 phím gõ accelerator được dịch ra
Ø Hàm OnCommand() sẽ xử lý message map đối với những thông tin gởi đi từ các ô điều khiển,các mục vào ON_COMMAND và cho gọi hàm thích ứng Ø Ta cho phủ quyết trong lớp dẫn xuất để giải quyết thông điệp
WM_COMMAND Một hàm phủ quyết sẽ không xử lý message map trừ khi được gọi bởi hàm OnCommand( ) thuộc lớp cơ sở
Ø Trị trả về : ứng dụng sẽ trả về trị nonzero nếu nó xử lý thông điệp bằng không trị trả về là 0
• Hàm OnInitDialog() :
v CDialog::OnInitDialog
v Virtual BOOL OnInitDialog()
Ø Hàm OnInitDialog( ) sẽ được gọi vào khi tất cả các ô điều khiển đã được tạo ra và trước khi khung đối thoại được hiển thị
Ø Việc thiết đặt mặc nhiên của hàm OnInitDialog() cũng cho gọi UpdateData() để thiết lập giá trị ban đầu của các ô điều khiển Điển hình là cho ta phủ quyết hàm OnInitDialog() để khởi gán về sau các ô điều khiển Hàm OnInitDialog() sẽ được gọi vào sau khi tất cả các ô điều khiển được tạo ra và trước khi khung đối thoại được hiển thị
• Hàm SetTimer() : khi ta gọi hàm SetTimer() , coi như ta yêu cầu Windows
tạo 1 system timer event, và không dùng đến hardware timer Trong 1 lúc, trên toàn bộ hệ thống chỉ có 16 system timer events là có thể được cho active Ta sử dụng SetTimer() để khởi động 1 timer lo gọi 1 thủ tục callback
Trang 7hoặc gởi 1 thông điệp WM_TIMER cho cửa sổ theo định kì được chỉ định Các thông điệp của timer bao giờ cũng được posted như là thông điệp WM_TIMER cho dù 1 thủ tục callback được cung cấp ,như vậy thông điệp timer có thể không được tiếp nhận đúng vào thời khoảng được khai báo Hàm SetTimer() sẽ trả về 1 trị số nguyên nhận diện timer mới nếu hàm
thành công Trị này sẽ được chuyển cho killtimer() để triệt tiêu timer Nếu
tất cả các timer đều đã được cấp phát hết(hàm không thành công), thì hàm sẽ trả về zero Hàm SetTimer có cú pháp như sau:
v CWnd::SetTimer
v UINT SetTimer(UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer) (HWND, UINT, UINT, DWORD));
Ø nIDEvent : chỉ ra mã nhận diện timer
Ø nElapse : cho biết khoảng thời gian ấn định tối thiểu (tính theo milliseconds)
cho phép trôi qua giũa hai thông điệp WM_TIMER Đây là trị số nguyên 16-bit đối với phiên bản Windows 3.1 hoặc 32-16-bit đối với Win32 Nếu trị này 16-bit thì thông số này từ 1 đến 65.535ms.Tuy nhiên việc này có thể đua đến nhầm lẫn Windows sử dụng hardware timer của máy tính như là nguồn tín hiệu timer định thời Hardware timer này lại đếm theo nhiệp độ cứ 1 clock stick là 54,925 ms Và Windows không thể thay đổ nhịp độ của hardware timer Do đó thời gian tối thiểu sẽ được thiết lập bởi hardware timer Do đó 2 hệ lục xảy ra :
Ø Windows chuển đổi trị của thông số nElapse thành 1 số nguyên clock stick Thí dụ, nếu bạn cho nElape=1000, thì Windows sẽ chuyển đổi thành 18,2 clock stick do việc chia 1000 cho 54,925 (1000/54,925=18,21 stick) Và số 18,2 stick này bằng 998,65 millisecond thay vì 1000 ms Khi nElapse nhỏ thua 55 ,thì cứ mỗi clock stick (55 ms ) ta mới nhận được thông điệp Ta không thể nhận 1 thông điệp timer thường xuyên hơn là mỗi môt 55 ms hoặc 18,2 thông điệp mỗi giây
Ø Các thông điệp WM_TIMER sẽ được đặt vào hàng nối đuôi giống như các thông điệp khác Do đó, nhịp độ mà ta nhận thông điệp timer tùy thuộc vào việc ứng dụng của ta cũng như các ứng dụng khác đi tìm các thông điệp từ hàng nối đuôi thế nào Nếu ứng dụng khác giữ CPU lâu hơn khoảng cách
Trang 8thời gian timer của ta thì ứng dụng của ta sẽ không tài nào nhận được thông điệp cần có
Ø lpfnTimer : chỉ rõ địa chỉ của việc ứng dụng cung cấp gọi lại hàm TimerProc
để xử lý thông điệp WM_TIMER Nếu thông số là NULL, thông điệp WM_TIMER bị thay thế trong hàng và mục quản thông điệp của ứng dụng bởi đối tượng CWnd
Ø Hàm callback của thông số lpfnTimer không cần phải mang tên TimerProc,
nhưng được định nghĩa như sau :
Ø Void CALLBACK EXPORT TimerProc(
HWND hWnd, // Mục quản của CWnd đã gọi // SetTimer
UINT nMsg, //WM_TIMER
UINT nIDEvent // mã nhận diện timer
DWORD dwTime); // Thời gian của hệ thống
• Hàm KillTimer() : Là hàm phá hủy timer đã chỉ ra ,nghĩa là hàm này ngưng
dòng thông điệp WM_TIMER do timer được khai báo bởi nIDEvent phát ra
Ta sẽ được bảo đảm là không nhận được thông điệp WM_TIMER sau khi đã
gọi đến hàm KillTimer() Ngoài ra hàm này còn cho gỡ bỏ bất cứ thông điệp
WM_TIMER nào còn nằm trên hàng nối đuôi các thông điệp Ta chỉ có thể thiết đặt một thông tri timer chỉ một lúc mà thôi bằng cách gọi hàm
SetTimer(), với một thời gian giới hạn nElapse nào đó thích hợp và hàm KillTimer() khi thông điệp WM_TIMER đến
v CWnd::KillTimer
v BOOL KillTimer( int nIDEvent);
Ø Trị trả về Non-zero nếu timer bị triệt tiêu, hoặ bằng 0 nếu không tìm thấy timer
• Hàm OnTimer() :
v CWnd::OnTimer
v Afx_msg void OnTimer(UINT nIDEvent); Ø nIDEvent : nhận diện mã ID timer
Trang 9Ø Hàm OnTimer() tương ứng với WM_TIMER Như vậy, ta có thể tạo nhiều
timer event, điển hình là cho nhiều thời gian khác nhau bằng cách gán các mã nhận diện ID khác nhau rồi chuyển chúng về cùng một hàm Window Ø Ta sử dụng trị của mã timer ID, NIDEvent để chỉ cho biết một timer đặt
biệt nào đó để ngưng khi gọi hàm KillTimer() Hiện không có hàm nào
điều chỉnh khoảng thời gian nElapse đối với một timer hiện hữu.Ta phải cho killtimer hiện hữu rồi cho tạo một timer mới với nElapse mới.Ta có thể sử dụng lại mã ID của timer vừa bị triệt tiêu :
Ø KillTimer (hWnd, nIDEvent);
Ø nTimerID = SetTimer(hWnd, nIDEvent, nNewElapse, NULL); • Srand() giống rand() :thiết đặt ngẫu nhiên điểm bắt đầu
v void srand( unsigned int seed ); v int rand( void );
Ø Khi sử dụng các hàm này trên môi trường Window ta phải khai báo : <stdlib.h> trên tập tin tiêu đề
v BOOL SubclassDlgItem( UINT nID, CWnd* pParent ); Ø nID : mã điều khiển
Ø pParent : cha của lớp điều khiển(thường là 1 dialog box) Ø Giá trị trả về nonzero nếu hàm thành công và ngược lại
Ø SubclassDlgItem gọi hàm thành viên này đến ‘phân lớp động’ (dinamically subclass),1 điều khiển được tạo từ 1 mẫu Dialog và gắn nó vào đối tượng CWnd Khi 1 điều khiển là phân lớp động thì thông điệp Windows sẽ gởi qua biểu đồ thông điệp của CWnd và gọi thông điệp những mục quản CWnd trước tiên Những thông điệp được thông qua lớp cơ sở sẽ được duyệt đến mục quản thông điệp mặc nhiên trong ô điều khiển
v CBitmapButton:
Ø Lớp này kế thừa của lớp CButton cho phép tạo những nút điều khiển mang hình ảnh bitmap thay vì là 1 nhãn văn bản trên mặt nút Một đối tượng CBitmapButton có thể những bitmap riêng biệt phản ánh tình trạng của nút bị ấn xuống, bị nhả ra, khi có focus hoặc cung cấp khi bị mờ Các
Trang 10đối tượng CBitmapButton chứa đến 4 bitmap phản ánh 4 trạng thái khác nhau của 1 nút Up (hoặc bình thường), down(được chọn), focused và disable Chỉ bitmap đầu tiên là bắt buộc có, các bitmap khác tùy ý
v LoadBitmaps() :
Ø Sử dụng hàm này khi ta muốn load mã những hình ảnh bitmap bằng tên nguồn hoặc số ID của chúng, hoặc khi ta không thể sử dụng hàm AutoLoad,vídụ như ta tạo 1 bitmap button vì nó không thừa kế lớp này
Ø CProgressCtrl là 1 cửa sổ ứng dụng có thể dùng để báo cho biết tiến độ thi hành trong 1 công tác kéo dài.Thanh này bao gồm 1 khung hình chữ nhật lần hồi được tô đầy, từ trái sang phải bởi 1 màu sắc
sáng ngời biểu hiện tiến triển công tác
Ø CprogressCtrl được kế thừa từ lớp CWnd , cung cấp mọi chức năng
cơ bản cho thanh tiến triển windows Thanh tiến triển thường có 1 khoảng cách (range) và 1 vị trí hiện hành Khoảng cách cho biết toàn bộ thời gian của công tác , còn vị trí hiện hành cho biết việc 'thi công' đã đến đâu