3.3.1.Lấy font hệ thống viết text và thao tỏc vẽ lờn màn hỡnh .
Mọi thao tỏc liờn quan đến hiển thị luụn luụn sử dụng mối liờn hệ logic : -Khai bỏo ngữ cảnh thiết bị (Device context :DC).
-Khai bỏo thành phần hiển thị
-Thực thi hiển thị trờn ngữ cảnh thiết bị.
Vỡ vậy trong mụi trường ứng dụng bao giờ cũng cú việc khai bỏo ngữ cảnh thiết bị trước khi tiến hành cỏc hoạt động cú liờn quan đến đồ hoạ .
Để cho chương trỡnh gọn và hợp lý, cụng việc thực thi hiển thị sẽ được viết riờng như là cỏc hàm cú sử dụng ngữ cảnh thiết bị, sau đú tiến hành khởi tạo đồ hoạ và cuối cựng là thao tỏc gọi hàm vẽ để hiển thị .
Điều thuận lợi trong VC++ đú là tớnh tương tỏc của cỏc thành phần trong một lớp rất cao, cỏc hàm trong một lớp được tạo ra một cỏch độc lập và được sử dụng khi được gọi tới mà khụng quan tõm đến vị trớ khai bỏo và định nghĩa chỳng. Cỏch tỏc động cỏc thành phần trong giao diện thụng qua cỏc biến điều khiển. Nú khiến cho một chương trỡnh VC++ nhỏ gọn và cú tớnh rừ ràng hơn rất nhiều .
Để khởi tạo đồ hoạ chỳng ta sử dụng sự kiện OnInitDialog tỏc động lờn lớp chớnh hiển thị (trong Dialog based là CprojectDlg ,ở SDI là
CProjectViewDlg …với Project là tờn của ứng dụng ).
Để khởi tạo, chọn sự kiện tỏc động OnInitDialog( ) và thờm đoạn code :
void CProjectDlg::OnInitDialog( ) {………
CRect KhungHienThi; //Khai bỏo một khung hỡnh chữ nhật để hiển thị //lờn nú
GetClientRect(KhungHienThi);// Khởi tạo cho Khung chữ nhật này
CClientDC dc(this;)//Khai bỏo ngữ cảnh thiết bị mang tờn dc (cú tỏc // dụng giống như giấy vẽ
pdc_Memory.CreateCompatibleDC(&dc);//pdc_Memory được khai //bỏo thuộc lớp CDC cú tỏc dụng như bỳt vẽ để vẽ lờn nền dc
m_NenBitmap.CreateCompatibleBitmap(&dc,KhungHienThi.Width( ), KhungHienThi.Height( ));
//m_NenBitmap được khai bỏo kiểu CBitmap, hàm
CreateCompatibleBitmap(..) thực hiện cụng việc kộo Bitmap m_NenBitmap vừa vặn
vào khung chữ nhật đó tạo ra. ………
return TRUE; }
Tạo ra cụng cụ hiển thị thường được viết riờng thành một hàm và sau đú mới được gọi tới. Hàm này thuộc sự quản lý của lớp hiển thị, khai bỏo hàm này như sau (trong file
CProjectDlg.h ) :
private :
void HàmHiểnThị(CDC*pDC);
void CProjectDlg::TenHam(CDC*pDC) {
//Khai bỏo bỳt vẽ nếu thực thi vẽ cỏc đường nột khung hỡnh trờn màn hỡnh:
CBrush ButVe(RGB( ..,…,…)); //với cỏc tham số của hàm RGB( )để chỉ //thị màu vẽ.
//Lấy ButVe vừa tạo làm bỳt vẽ hiện thời chuẩn bị cho cụng việc vẽ . CBrush *pOldButVe=pDC->SelectObject(&ButVe);
//Cỏc thao tỏc vẽ lờn màn hỡnh
pDC->HàmVẽ( tham số );
//Sau khi vẽ xong phải giải phúng bộ nhớ sau khi hoàn tất việc vẽ : pDC->SelectObject(pOldButVe);
//Làm tương tự với cỏc lớp CPen và CFont khi muốn thực hiện thao tỏc với chỳng.
………… }
Sau khi đó chỉ ra cỏch thức hiển thị ( Hàm được tạo ra để hiển thị) và cỏc vận dụng chuẩn bị cho cụng việc hiển thị (khởi tạo đồ hoạ ) giờ chỉ là cụng việc thực thi hiển thị. Cụng việc này sẽ được thực hiện nhờ sự kiện Paint trong lớp hiển thị chớnh .
void CProjectDlg::Paint( ) {………
else {
CPaintDC dc(this); //Khai bỏo ngữ cảnh thiết bị
//Gọi hàm hiển thị với tham số &dc để tiến hành hiển thị //HàmHiểnThị(&dc);
UpdateData(FALSE);//Hàm này cú tham số FALSE khi muốn
//đưa dữ liệu trong chương trỡnh ra màn hỡnh và cú tham số TRUE khi nhập //dữ liệu từ bờn ngoài vào.
……….
CDialog::OnPaint( ); }
}
Vớ dụ dưới đõy minh họa cho một đoạn text chạy trong một khung chữ nhật được vẽ lờn màn hỡnh hiển thị . Đầu tiờn khởi động VC++ 6.0, vào File>New để mở một ứng dụng MFC AppWizard và đặt tờn chương trỡnh là VD > ấn ok để chuyển sang bước tiếp theo :
Hỡnh3.34 .Tạo
Chọn kiểu ứng dụng là Dialog based và ấn Finish để khởi tạo chương trỡnh.Vớ dụ sẽ viết một đoạn text (gỏn cho một biến toàn cục m_auto)và di chuyển trong giao diện chương trỡnh ứng dụng. Cụng việc hiển thị này sẽ được hàm OnPaint( )xử lý, tuy nhiờn để cho hàm này nhỏ gọn ta tạo một hàm OnDraw(CDC* pDC) riờng biệt để làm điều này . Để dũng chữ chạy được cần phải cú sự kiện WM_TIMER.
Khai bỏo cỏc biến và hàm liờn quan trờn header file VDDlg.h và viết lệnh trờn file nguồn VDDlg.cpp .
Hỡnh 3.35. Khai bỏo cỏc biến và hàm trong header file VDDlg.h
Hàm OnDraw sẽ được sử dụng để vẽ lờn màn hỡnh, biến m_auto được sử dụng để nhập đoạn text (Chẳng hạn được gỏn là “Trường Đại Học Bỏch Khoa Hà Nội” với font VnArial).
Viết mó lệnh cho hàm OnDraw trong file nguồn VDDlg.cpp :
Hỡnh3.36 .Viết Code cho hàm OnDraw
Để thực hiện được viết chữ trờn màn hỡnh đoạn mó lệnh :
OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,DEFAULT_PITCH,".VnTime"); CFont*pOldFont=pDC->SelectObject(&font);
Hàm CreateFont này cú 14 tham số và được định nghĩa(đó cú sẵn trong thư viện CFont và khụng phải định nghĩa lại trong ứng dụng) như sau :
BOOL CreateFont(
int nHeight,//Chiều cao font chữ .
int nWidth,//Chiều rộng trung bỡnh cỏc kớ tự.
int nEscapement,//Phương và chiều mà văn bản được in ra trờn //màn hỡnh
int nOrientation,// Gúc nghiờng giữa 2 kớ tự kề nhau int nWeight, //Độ đậm nột của font chữ
BYTE bITalic, //xỏc định sự kiện kớ tự nghiờng hay khụng nghiờng BYTE bUnderline, // Xỏc định xem cú gạch dưới văn bản hay //khụng.
BYTE cStrikeOut,//Xỏc định sự kiện cú kẻ đường gạch ngang giữa //văn bản hay khụng
BYTE nCharSet,//Tập kớ tự phụng chữ
BYTE nOutPrecision,/ /Xỏc định mối liờn hệ giữa kết quả hiển thị //với cỏc thuộc tớnh chiều cao, chiều rộng, phương chiều văn bản . BYTE nClipPrecision,// Liờn quan đến cắt xộn kớ tự ngoài khung //hiển thị
BYTE nQuanlity,// Chất lượng hiển thị
BYTE nPitch andFamily,//Xac định bước phụng chữ (khoảng cỏch //giữa 2 kớ tự)
LPCTSTR lpszfaceName,//Kiểu font
Bắt buộc phải cú trong hàm này để khởi tạo ra font của đoạn text cần hiển thị ,con trỏ
pDC thực hiện ghi đoạn text lờn màn hỡnh bằng cõu lệnh :
pDC->TextOut(0,180,m_auto);
với tham số “0,180” chớnh là toạ độ của vị trớ bắt đầu chạy của đoạn text trờn màn hỡnh và m_auto chớnh là nội dung hiển thị, nú là một xõu kớ tự và sẽ được định trong hàm
OnInitDialog( ).Trước đú định kiểu nền và màu chữ :
pDC->SetBkMode(TRANSPARENT); pDC->SetTextColor(RGB(255,56,88));
Hỡnh 3.37.Code được viết trong hàm OnInitDialog( ).
Sử dụng VietKey hoặc Unicode để gừ đoạn text tiếng Việt gỏn cho m_auto, khởi tạo ngữ cảnh thiết bị (Device Context, DC), hàm OnDraw sẽ vẽ lờn trờn DC này. biến CDC
m_pdcMemory sẽ thực hiện vẽ trờn nền của m_pBitmap lấy nền là kớch thước của cửa
sổ màn hỡnh .
Sau khi khởi tạo đồ họa bắt đầu thực hiện cụng việc hiển thị ra màn hỡnh bằng cỏch tỏc động đến hàm OnPaint( ) : void CVDDlg::OnPaint( ) { ………. else { CPaintDC dc(this); CRect rectUpdate; dc.GetClipBox(&rectUpdate); CBitmap*pOldBitmap=m_pdcMemory.SelectObject(&m_pBitmap); m_pdcMemory.SelectClipRgn(NULL); m_pdcMemory.IntersectClipRect(&rectUpdate); CBrush backgroundBrush(RGB(192,192,192)); CBrush*pOldBrush=m_pdcMemory.SelectObject(&backgroundBrush); m_pdcMemory.PatBlt(rectUpdate.left,rectUpdate.top, rectUpdate.Width(),rectUpdate.Height( ),PATCOPY) OnDraw(&m_pdcMemory); dc.BitBlt(rectUpdate.left,rectUpdate.top, rectUpdate.Width(),rectUpdate.Height(), &m_pdcMemory,rectUpdate.left,rectUpdate.top,SRCCOPY); m_pdcMemory.SelectObject(pOldBitmap); m_pdcMemory.SelectObject(pOldBrush); CDialog::OnPaint(); }
}
Hàm OnDraw ở đõy được gọi tới để vẽ lờn ngữ cảnh thiết bị bằng sử dụng than sử dụng tham số &m_pdcMemory .
Đến đõy ấn F5 để dịch chương trỡnh nhưng mới chỉ hiện thỉ chữ nhưng chưa chuyển động .Thờm sự kiện WM_TIMER cho lớp CVDDlg để cho chữ chuyển động :
Ấn Ctrl+W, chọn lớp CVDDlg, và chọn Messages :
Hỡnh 3.38. Thờm sự kiện WM_TIMER để cho chữ chuyển động. void CVDDlg::OnTimer(UINT nIDEvent)
{
CString str;
str=m_auto.Left(1);//Thực hiện dịch chuyển đoạn text sang trỏi m_auto.Delete(0.1);
m_auto=m_auto+str; //Đoạn text hiển thị mới sẽ là đoạn text //dịch chuyển từ trỏi sang phải
InvalidateRect(CRect(0,0,600,600),FALSE); CDialog::OnTimer(nIDEvent);
}
Tốc độ dịch chuyển của đoạn text sẽ được hàm SetTimer đặt trong OnInitDialog( ) (Ở đõy là SetTimer(1,500,NULL) .
Hỡnh 3.39 .Kết quả của chương trỡnh.
3.3.2.Thiết kế một Dialog riờng đưa nú vào Dialog chớnh , cập nhật giờ hệ thống.
Trong mụi trường ứng dụng Dialog Based thường phải thiết kế thờm cỏc Dialog phụ.Thiết kế một Dialog khỏc trong ứng dụng hoàn toàn tương tự như thiết kế giao diện chớnh .Thao tỏc chốn thờm một Dialog khỏc tương tự như khi thờm một menu hay toolbar. Sau khi thiết kế xong sẽ tiến hành đưa nú vào ứng dụng . VD đơn giản sau đõy sẽ chỉ dẫn một cỏch cụ thể việc thiết kế một menu riờng và cỏch đưa nú vào menu chớnh :
Mở một một ứng dụng MFC AppWizard trong mụi trường phỏt triển Dialog Based và đặt tờn ứng dụng là TangThoiGian .
Yờu cầu :cỏc thụng số đầu vào là giờ, phỳt, giõy, chỳng được đưa vào nhờ một hộp thoại khỏc (chớnh là Dialog phụ ).
Trong vựng làm việc kớch chuột vào Resource View và mở rộng phần Dialog , chọn
IDD_DIALOG_CHANGE để thiết kế giao diện, dựng cỏc thành phần trong Control toolbar.
Hộp thoại phụ :gồm cú :
-Cỏc EditBox : IDC_EDIT_HOUR, IDC_EDIT_MINUTE và IDC_EDIT_SECOND đặt ở trạng thỏi Disable .
-Cỏc Static Text : Hour(IDC_STATIC), Minute, Second .
-Nỳt bấm Edit (IDC_BUTTON_EDIT ) cú tỏc dụng khi bấm vào thỡ cỏc Edit box chuyển sang trạng thỏi Enable và cú thể hiệu chỉnh được giỏ trị của chỳng .Sau khi bấm Edit thỡ trạng thỏi của bản thõn nỳt bấm này ở trạng thỏi Disable.
-Nỳt bấm Ok (để mặc định khi tạo ra Dialog này ) : cú tỏc dụng khi bấm vào sẽ thoỏt khỏi hộp thoại Change .
Hỡnh 3.40 .Hộp thoại phụ
Sau khi thiết kế xong hộp thoại phụ cần tạo ra một lớp riờng để tỏc động lờn nú, ấn
Ctrl+ W xuất hiện hộp thoại thụng bỏo :
Hỡnh 3.41. Thờm lớp quản lý hộp thoại phụ
Chọn Create a new class để tạo ra một lớp mới và đặt tờn :
Hỡnh 3.42. Đặt tờn lớp là CChangeDlg
Và giờ trong ứng dụng đó cú sự hiện diện của lớp này, kiểm tra sự cú mặt của nú trong cõy thư mực Class View .
-Thờm một biến logic m_tedit để điều khiển hoạt động của nỳt Edit( khai bỏo trong
ChangeDlg.h ngay dưới dũng “DECLARE_MESSAGE_MAP( )”
private :
BOOL m_tedit;
Ấn Ctrl+W, chọn lớp CchangeDlg, chọn tab Member Variables để thờm cỏc biến cho cỏc edit box (chọn Control ID> Add Variable ) :
Hỡnh 3.43.Thờm cỏc biến cho EditBox.
Hỡnh 3.44.Khai bỏo biến cho cỏc Edit Box
Đến đõy đó hoàn tất cụng việc khai bỏo .Chuyển sang phần viết Code cho Dialog “Change” này . Điều này hoàn toàn độc lập đối với việc viết code với Dialog chớnh. Hoàn toàn cú thể thiết kế giao diện chớnh và giao diện phụ sau đú mới viết code . Tuy nhiờn nờn tư duy mụđun hoỏ từng phần .
Viết code cho hộp thoại này gồm cỏc cụng việc : -Với sự kiện bấm vào nỳt Edit :
*Kiểm tra xem sự kiện nỳt bấm Edit cú diễn ra khụng bằng cỏch sử dụng biến BOOL
m_tedit xem cú nhận giỏ trị TRUE hay khụng : if(m_tedit)
* Làm cho cỏc Edit Box chuyển sang trạng thỏi Enable để cú thể hiệu chỉnh bằng lệnh :
SetDlgItem(thamsốhàm )->EnableWindow(TRUE) ;
Hàm SetDlgItem sẽ tỡm đến địa chỉ điều khiển là tham số của hàm .
“->” là dấu hiệu cho thấy tỏc động của hàm tiếp theo sau đú.EnableWindow (BOOL) sẽ làm cho đối tượng ở trạng thỏi Enable khi hằng số BOOL là TRUE và sẽ ở trạng thỏi
Disable (khụng hiệu chỉnh được đối tượng ) khi BOOL là FALSE.
*Cập nhật dữ liệu lờn màn hỡnh bằng hàm UpdateData(FALSE ) ,tham số sẽ là TRUE nếu như lấy dữ liệu từ ngoài chương trỡnh đưa lờn màn hỡnh .
-Dữ liệu cần thay đổi là cỏc thụng số của EditBox, chỳng sẽ ngầm gỏn cho giỏ trị cỏc biến int là m_edit_hour,m_edit_minute,m_edit_second .
void CChangeDlg::OnButtonEdit( ) { m_tedit=TRUE; if(m_tedit) { GetDlgItem(IDC_BUTTON_EDIT)->EnableWindow(FALSE); GetDlgItem(IDC_EDIT_HOUR)->EnableWindow(TRUE); GetDlgItem(IDC_EDIT_MINUTE)->EnableWindow(TRUE); GetDlgItem(IDC_EDIT_SECOND)->EnableWindow(TRUE); UpdateData(FALSE); } }
Tiếp theo sẽ thiết kế Giao diện chương trỡnh chớnh và viết code cho nú :
Hỡnh 3.45.Hộp thoại chớnh
Chọn IDD_TANGTHOIGIAN_DIALOG (tờn tự đặt ) và thiết kế giao diện gồm cỏc thành phần :
-Cỏc EditBox : IDC_HOUR, IDC_MINUTE, IDC_SECOND ở trạng thỏi Disable . -Cỏc nỳt bấm Change,Begin
Hỡnh 3.46.Thờm cỏc biến điều khiển .
Nhưng trước tiờn thờm cỏc biến trung gian cú nhiệm vụ thu nhận dữ liệu từ hộp thoại Change truyền xuống sau đú mới gỏn cỏc biến của cỏc EditBox trong giao diện chớnh. Trong Files View ở vựng làm việc mở rộng mục Header File và chọn
CTangThoiGianDlg.h để tiến hành khai bỏo trung gian này :
class CTangThoiGianDlg : public CDialog { ………. DECLARE_MESSAGE_MAP( ) public: int m_hour,m_minute,m_second; };
Hoạt động của chương trỡnh : khi bấm vào nỳt Change sẽ mở hộp thoại Change để thu nhận cỏc giỏ trị mới của giờ, phỳt , giõy và đặt lờn cỏc biến trung gian .Tăng giỏ trị “giõy” lờn 1. Thực hiện cụng việc kiểm tra xem cỏc giỏ trị giờ >= 24 ?, phỳt>=60,giõy>=60 hay khụng rồi sửa lại sau đú gỏn lờn cỏc edit box .Cài đặt sự kiện
WM_TIMER để hiển thị được sự thay đổi của cỏc edit box bằng cỏch cài đặt cho nỳt
bấm Begin một bộ định thời trước khi hiện kết quả . Ấn Ctrl+W :
Hỡnh 3.47.Sử dụng sự kiện WM_TIMER.
Tỡm đến CTangThoiGianDlg.cpp trong Source File để viết code cho cỏc hàm .
void CTangThoiGianDlg::OnChange( ) {
CChangeDlg dlg;/ /thờm biến này để quản lý hộp thoại Change
if(dlg.DoModal( )==IDOK) //Kiểm tra hộp thoại Change sau đú mới //lấy tham số
{
m_hour=dlg.m_edit_hour; //Gỏn cỏc giỏ trị trong EditBox cho cỏc //biến trung gian
m_minute=dlg.m_edit_minute;// m_second=dlg.m_edit_second;//
UpdateData(FALSE);// Cập nhật dữ liệu
} }
void CTangThoiGianDlg::OnBegin( ) //Sự kiện bấm vào nỳt Change
{
GetDlgItem(IDC_HOUR)->EnableWindow(TRUE);//Làm hiệu lực //cỏc Edit box để hiển thị
GetDlgItem(IDC_MINUTE)->EnableWindow(TRUE); GetDlgItem(IDC_SECOND)->EnableWindow(TRUE);
SetTimer(1,100,NULL);// Đặt bộ đếm thời gian để hiển thị dữ liệu //trờn EditBox và đặt tờn bộ đếm này là 1 để quản lý
UpdateData(FALSE); }
//Bộ đếm thời gian để hiển thị được sự thay đổi trờn màn hỡnh
{
if(nIDEvent= =1)//Kiểm tra sự kiện bấm nỳt Begin thụng qua tờn của bộ //đếm đó khai bỏo khi cú sự kiện bấm nỳt Begin
{
m_second++; //Tăng biến trung gian mỗi lần lờn 1 đơn vị
if(m_second>=60) //Kiểm tra xem cú vượt quỏ giỏ trị giới hạn hay
//khụng
{
m_second%=60; //Lấy giỏ trị mới của m_second là phần //nguyờn của phộp chia m_second cho 60
m_minute++; if (m_minute>=60) { m_minute%=60; m_hour++; if(m_hour>=24) { m_hour%=24; } } }
m_h=m_hour; //Gỏn cỏc biến trung gian lờn EditBox
m_m=m_minute;// m_s=m_second;// UpdateData(FALSE);//Cập nhật dữ liệu ra màn hỡnh . } CDialog::OnTimer(nIDEvent); } Ấn F5 để biờn dịch chương trỡnh .