MFC – Lession2: Biến và controls

Trong ví dụ này ta sẽ tạo ra một cửa sổ minh họa việc đăng nhập. Khi nhập đúng username và password, chương trình sẽ hiển thị thông điệp chào mừng, nếu không thì chương trình sẽ yêu cầu nhập lại, nhập sai 3 lần chương trình sẽ thoát.
Download source-code(742KB)


Giới thiệu

Các nội dung sẽ trình bày

–       Khai báo biến thành viên lớp

–       Cơ chế DDX/DDV

–       Sử dụng các control cơ bản

–       Các chức năng phụ trong thiết kế cửa sổ.

Thiết kế

LoginDialog

–       Bạn tạo ứng dụng MFC kiểu dialog based như bài trước, vẽ các Edit box, Static Text, Radio Button và Button vào để tạo giao diện như hình sau, chú ý rằng các control luôn đặt ID là chữ in hoa và bắt đầu bằng IDC_:

FormDesign

–       Để văn bản trong trường Pasword hiển thị thành các dấu sao ‘*’, bạn nhấn phải vào IDC_PASSWORD chọn Properties, qua thẻ Styles đánh dấu chọn mục Password.

–       Mở hộp thoại Properties của IDC_USER và đánh dấu chọn vào mục Group.

–       Ghi chú: Radio Button đầu tiên trong một nhóm cần được nhóm lại để chỉ ra rằng các Radio Button phía sau sẽ thuộc cùng nhóm với Radio Button này.

Thêm biến vào chương trình

a.      Quy ước đặt tên biến

–       Quy ước đặt tên các biến thành viên của lớp là sử dụng tiền tố m_ để phân biệt với các biến cục bộ. Ngoài ra còn sử dụng các kí hiệu Hungary để phân biệt kiểu dữ liệu như bảng sau:

Prefix

Data Type
a array
b BOOL
by BYTE
c char, WCHAR, TCHAR
C class
d double
dw DWORD (unsigned long)
l long
w WORD
f float
h Windows handle
i int
n short
s string
sz

Chuỗi kết thúc bởi kí tự 0

b.      Thêm biến thành viên vào lớp

–       Chương trình cần một biến để đếm số lần đăng nhập thất bại của người dùng, ta sẽ đặt biến này trong lớp CLoginDlg. Theo các bước sau:

  • Chọn thẻ ClassView trong WorkSpace, nhấn phải chuột vào mục CLoginDlg chọn ‘Add Member Variable’.
  • Trong hộp thoại Add Member Variable hiện ra bạn đánh int vào Variable Type và m_iLoginCount vào Variable Name:
  • Chọn phạm vi truy xuất là Private trong mục Access. Nhấn OK.

c.      Cơ chế DDX/DDV

–       MFC cung cấp cơ chế DDX/DDV giúp liên kết control với các biến dữ liệu. Hai cơ chế này gắn liền với nhau và đảm bảo việc trao đổi dữ liệu giữa biến và control được chính xác và hợp lệ.

  • DDX (Dialog Data Exchange): Trao đổi dữ liệu qua lại giữa control và các biến. Dữ liệu được nhập vào control sẽ được cập nhật vào biến và giá trị của biến sẽ được hiển thị lên control tương ứng.
  • DDV (Dialog Data Validate): kiểm tra tính hợp lệ của dữ liệu khi chuyển từ control đến biến. Khi phát hiện kiểu dữ liệu không hợp lệ, cơ chế này tự phát sinh thông điệp nhắc nhở để người dùng nhập lại.

–       Để chuyển dữ liệu nhập từ các control vào biến, bạn sử dụng hàm UpdateData() với tham số là TRUE. Ngược lại để chuyển dữ liệu từ biến sang control, bạn cũng dùng UpdateData() nhưng với tham số là FALSE.

–       Thông thường bạn sẽ gọi UpdateData(TRUE) trước khi bắt đầu sử dụng các biến và gọi UpdateData(FALSE) sau khi sử dụng để hiển thị dữ liệu kết quả lên các control.

d.     Gán biến thành viên vào các control

–       Để thực hành cơ chế DDX/DDV này và làm việc với các control, ta sẽ dùng ClassWizard để gán biến vào các control cần thiết. Bạn hãy làm theo các bước sau:

–       Nhấn phải chuột vào IDC_USERNAME chọn ClassWizard, trong mục Control IDs chọn IDC_USERNAME_EDIT và nhấn nút Add Variable.

–       Tại hộp thoại Add Member Variable, phần Member variable name đang được focus, bạn đặt tên cho biến là m_sUsername. Bởi vì giá trị của biến ta cần làm việc là kiểu văn bản nên bạn sẽ đặt theo mặc định Category là Value và Variable type là CString.

AddMemberVariable

–       Tương tự bạn gán thêm biến m_sPassword cho control IDC_PASSWORD và biến m_iLoginType (kiểu int) cho IDC_USER. Nhấn OK và bạn sẽ có hình sau:

MemberVariables

–       Lý do biến gán cho Radio Button là kiểu int vì biến này sẽ có giá trị dựa vào thứ tự của Radio Button được chọn trong nhóm. Trong ví dụ này khi bạn chọn kiểu đăng nhập là User (IDC_USER) thì biến sẽ có giá trị là 0, và nếu chọn Admin thì giá trị sẽ là 1.

–       Nhấn OK để đóng hộp thoại.

Thiết kế bằng bảng thuộc tính

–       Qua các bước trên, ta có thể tạo một bảng thuộc tính các control và biến để thực hành nhanh chóng.Trong các bài tiếp theo tôi sẽ dùng bảng này để hướng dẫn bạn làm bước thiết kế.

Đối tượng

Thuộc tính Giá trị Biến
Edit box ID IDC_USERNAME CString m_sUserName
Edit box IDStyles > Password IDC_PASSWORDChecked CString m_sPassword
Radio Button IDGroup IDC_USER
Checked
int m_iLoginType
Radio Button ID IDC_ADMIN
Button ID IDC_OK_BUTTON
Button ID IDC_CANCEL_BUTTON

Viết mã lệnh

–       Bây giờ bạn có thể chạy thử chương trình và nhận thấy rằng cả hai Radio Button trên form đều không được chọn. Để khi chương trình chạy sẽ mặc định chọn Radio Button IDC_USER, bạn cần gán giá trị cho biến m_iLoginType bằng 0 trong hàm CLoginDlg::OnInitDialog(). Hàm này sẽ được thực thi khi cửa sổ Login được tạo ra.

–       Bạn chuyển qua thẻ ClassView trong WorkSpace, mở rộng nhánh CLoginDlg, nhấn chuột phải vào mục OnInitDialog() và chọn ‘Go to Definition’ (hoặc nhấn đôi chuột) để nhảy đến phần định nghĩa của hàm này. Phần viết code của bạn sẽ bắt đầu từ dòng chú thích ‘TODO: Add extra initialization here’. Trong hàm này ta cũng thực hiện việc gán giá trị ban đầu cho m_iLoginCount bằng 0.

BOOL CLoginDlg::OnInitDialog()

{

CDialog::OnInitDialog();

[…]

// TODO: Add extra initialization here

m_iLoginCount=0;

m_iLoginType=0;

UpdateData(FALSE);

return TRUE;  // return TRUE  unless you set the focus to a control

}

–       Bạn hãy dùng chức năng ClassWizard để thêm sự kiện cho IDC_OK và IDC_CANCEL tương ứng là OnOkButton() và OnCancelButton().

–       Sau đó viết mã lệnh cho từng hàm như sau:

void CLoginDlg::OnCancelButton()

{

OnCancel();

}

void CLoginDlg::OnOkButton()

{

if(m_iLoginCount==2)

{

MessageBox(“You have used 3 out of 3 login attempts. Program will exit now”);

SendMessage(WM_CLOSE);

return;

}

UpdateData(TRUE);

CString sUserName;

CString sPassword;

if (m_iLoginCount==0)

sUserName=sPassword=”user”;

else

sUserName=sPassword=”admin”;

if(m_sUserName!=sUserName || m_sPassword!=sPassword)

{

MessageBox(“Invalid username or password. Please try again”);

m_sPassword=””;

UpdateData(FALSE);

m_iLoginCount++;

}else

{

MessageBox(“Welcome to C++ World”);

}

}

–       Hàm UpdateData() như đã giới thiệu trong phần trước có chức năng quan trọng giúp cập nhật giá trị của biến và các control tương ứng với chúng.

–       Khi tham số truyền vào UpdateData() là TRUE, các biến m_sUsername, m_sPassword và m_iLoginType sẽ được cập nhật giá trị từ IDC_USERNAME, IDC_PASSWORD_EDIT và các Radio Button trên form. Ngược lại nếu tham số này là FALSE, các giá trị của m_sUsername, m_sPassword, m_iLoginType sẽ được cập nhật và hiển thị lên các Edit box và Radio Button tương ứng.

–       Sau khi gọi UpdateData(TRUE), ta kiểm tra nếu username hoặc password người dùng nhập vào không chính xác thì sẽ xuất hiện thông báo “Invalid username or password. Please try again”, ngược lại nếu đúng thì sẽ hiện ra “Welcome to C++ World”.

–       Đầu tiên ta sẽ kiểm tra biến m_iLoginCount nếu như bằng 2 có nghĩa là đã đăng nhập sai 3 lần (vì tính từ 0), ta sẽ cho hiển thị thông báo và gửi một thông điệp yêu cầu đóng cửa sổ bằng hàm SendMessage với tham số WM_CLOSE.

–       Trong đoạn mã trên ta gán m_sPassword=”” trước khi gọi UpdateData(FALSE) để khi người dùng đăng nhập sai, chương trình sẽ xóa nội dung trong Edit box IDC_PASSWORD.

–       Bạn có thể muốn con trỏ nhập văn bản tự động nhảy vào Edit box IDC_PASSWORD khi người dùng đăng nhập. Bạn hãy chèn đoạn này sau câu lệnh m_iLoginCount++:

CEdit * pEdit;

pEdit = (CEdit *)GetDlgItem(IDC_PASSWORD);

pEdit->SetFocus();

–       Đoạn mã trên tạo một đối tượng Edit box (có kiểu CEdit) và dùng hàm GetDlgItem() để lấy về một con trỏ kiểu CWnd của control dựa vào ID của nó. Sau khi ép kiểu sang CEdit* ta có thể sử dụng các phương thức của control Editbox thông qua toán tử ->. Đây là toán tử thay thế cho toán tử chấm ‘.’ để truy xuất các thành viên của đối tượng kiểu con trỏ. Sau đó ta gọi SetFocus() để chuyển focus đến Edit box này.

–       Bây giờ bạn có thể chạy thử và xem kết quả.

Các chức năng phụ

a.      Di chuyển focus giữa các control

–       Trong cửa sổ chương trình đang làm việc chỉ có một control có thể nhận các input của người dùng tại một thời điểm, ta gọi control đó đang được focus. Bạn có thể di chuyển focus này giữa các control bằng cách sử dụng phím Tab trên bàn phím (chức năng Tab Order) hoặc bằng phím tắt là một kí tự kết hợp với phím Alt (chức năng mnemonic). Trong phần này bạn sẽ học cách để làm việc với 2 chức năng này.

1.      Tab Order

–       Để sử dụng chức năng này bạn cần mở hộp thoại ở chế độ thiết kế. Sau đó chọn menu Layout > Tab Order hoặc dùng phím tắt Ctrl+D. Khi đó bạn thấy mỗi control sẽ xuất hiện một số bên cạnh chỉ ra thứ tự của chúng khi bạn nhấn phím Tab để di chuyển focus. Các số nhỏ hơn sẽ nhận focus trước cho đến khi đến số cuối cùng và lặp lại từ đầu.

–       Bạn hãy dùng chuột click vào các số đó để thay đổi giá trị cho phù hợp

TabOrder

2.      Mnemonic

–       Ta sẽ dùng chức năng này cho nút OK để khi người dùng nhấn Alt+O thì nút OK sẽ được kích hoạt. Chú ý là kí tự đi kèm trong phím tắt nằm trong caption của control, nên bạn hãy chọn lựa hợp lí để tránh việc nhiều control sử dụng cùng kí tự làm phím tắt. Ưu tiên cho control nào được sử dụng nhiều và kí tự được chọn thường là kí tự đứng đầu tiên của caption.

–       Bạn nhấn phải vào nút OK chọn Properties, trong phần Caption bạn thêm dấu & vào trước chữ ‘O’, caption của nút OK bây giờ là ‘&OK’.

–       Đóng cửa sổ Properties lại bạn có thể thấy bên dưới chữ ‘O’ của nút OK được gạch chân. Bạn hãy chạy thử và nhấn Alt+O, hộp thoại thông điệp hiện ra chứng tỏ nút OK vừa được kích hoạt.

–       Tương tự bạn sửa caption của nút Cancel thành ‘&Cancel’ để gán phím tắt Alt+C cho nút này.

–       Bạn có thể thắc mắc là làm sao để đặt mnemonic cho Edit box và tại sao các Static Text cũng có thể gán được mnemonic trong khi chúng không xử lý sự kiện gì cả. Thực ra khi bạn cố focus đến một Static Text, thì cửa sổ sẽ chuyển focus đến control có tab order ngay phía sau nó. Lợi dụng điểm này, bạn có thể gán mnemonic để focus đến Edit box như sau:

  • Chỉnh sửa tab order như hình trên. Tức là tab order của Edit box lớn hơn 1 so với Static Text bên cạnh nó.
  • Sửa caption của 2 Static Text thành &User Name và &Password.

–       Bây giờ bạn có thể chạy thử và dùng các phím Alt+U, Alt+P, Alt+O, Alt+C để chuyển focus đến các control trong cửa sổ.

b.     Thay thế icon của cửa sổ

–       Khi tạo ra một cửa sổ dialog based, VC++ tự động gán cho cửa sổ một icon mặc định trên thanh tiêu đề. Trong hầu hết các ứng dụng, bạn phải thay thế nó bằng một icon khác đặc trưng cho sản phẩm của mình. Để làm việc này bạn thực hiện theo các bước sau:

  • Mở phần ResourceView trong Workspace
  • Mở rộng nhánh icon và bạn sẽ thấy một mục con là IDR_MAINFRAME, nhấn đôi vào đó để mở giao diện thiết kế icon.
  • Sử dụng các công cụ vẽ được cung cấp sẵn để thiết kế lại icon.
  • Sau đó bạn hãy biên dịch và chạy chương trình để xem icon trên thanh tiêu đề cửa sổ đã được thay đổi.Edit Icon

https://yinyangit.wordpress.com

Advertisements

12 thoughts on “MFC – Lession2: Biến và controls

  1. Em đang làm 1 bài tập lớn em muốn mọi người chỉ giùm em với
    em tạo 1 dialog gom có 1 button là Open và em đã lấy đc dữ liệu nhưng của em nó đc lưu trong file txt trong project em muốn cho kết quả em tìm đc hiện lên trên dialog thì em làm phải làm thế nào do em mới học nên không biết nhiều lắm.

    if (cMessageType == IAM)
    {
    pIAMInfo = (PIAM_INFO)GetIAMMessage(PointerOfData, iDataLength);
    if (pIAMInfo)
    {
    iIAM ++;
    printf(“\n%d<——%d\n", iPacketRead, iPacket);
    fprintf(rFile, "\n%dcalling_number, pIAMInfo->called_number);
    }
    //pCallInfo = (CALL_INFO *)HIndexGetEx(&HTListIAM, (void *)cCIC);
    }

    //end of read multimessage
    iLengh = HextoDec(pDataChunk->chunk_length, 2);
    PointerOfMessage = PointerOfMessage + iLengh;
    iMessageLength = iMessageLength – iLengh;

    // [5/28/2012 doducanh]
    iPacketRead ++;

    // fprintf(rFile, “\n\t\t%d\t<– %d", iPacketRead, iPacket);
    // [5/28/2012 doducanh]
    if (iMessageLength == 0)
    {
    break;
    }
    }//end of while
    }
    }
    }
    }
    }

    fclose(rFile);
    }

    em bắt được rồi nhưng em muốn cho những thông tin hiện lên trên 1 group box
    anh có thể chỉ em với được không ạ?

    Phản hồi

Trả lời

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Đăng xuất / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Đăng xuất / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Đăng xuất / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Đăng xuất / Thay đổi )

Connecting to %s