Trong bài tập tổng hợp KTLT này, chúng tôi đã thực hiện việc xây dựng một menu giúp tiếp nhận lựa chọn của người dùng để từ đó gọi ra chức năng thích hợp và xử lý. Nhược điểm của menu này là người dùng phải lựa chọn bằng cách gõ số.
Giờ đây, chúng tôi muốn cải tiến nó hơn bằng việc sẽ cho phép người dùng sử dụng phím mũi tên để di chuyển lên xuống giữa các tùy chọn trong menu. Tùy chọn nào đang focus sẽ đươc highlight để người dùng nhận biết. Nếu muốn chọn chức năng nào, chỉ cần nhấn phím Enter để thực hiện.
Demo menu đã hoàn tất
Ý tưởng để thực hiện menu này đó là chúng ta sẽ cần phải xác định option nào đang được focus dựa vào vị trí index của nó. Sau đó chúng ta sẽ in ra menu với chỉ riêng option đó được tô màu hightlight. Bản chất ở đây chính là xóa đi vẽ lại menu liên tục mỗi khi người dùng bấm phím Lên hoặc Xuống.
Khác với những bài trước chúng ta hardcode menu, thì lần này chúng ta sẽ khai báo các option trong menu là một mảng chuỗi. Sau đó in ra menu bằng vòng lặp.
...
string menu[] = {
"Add new record" ,
"Edit record",
"Delete record",
"Search record",
"List all records",
"Trash",
"Quit"};
...
Để tính độ dài của mảng trong C/C++, chúng ta cài đặt như sau:
...
int len = sizeof(menu)/sizeof(menu[0]);
...
Cài đặt hàm in menu đơn giản từ mảng có sẵn. Chúng ta sẽ truyền vào biến focus là vị trí index của option đang được highlight từ đó tô màu riêng cho option này.
...
// focus: là index của option đang được hightlight
// len: độ dài của mảng option
void printMenu(int focus, int len) {
clrscr(); // xoa man hinh
for (int i = 0; i < len; i++) {
cout << i+1 << ". " << menu[i] << endl;
}
}
...
Để cài đặt màu cho text console, chúng ta sử dụng method sau trong thư viện windows.h với COLOR_CODE là một số trong khoảng từ 1 tới 254.
...
SetConsoleTextAttribute(hConsole, COLOR_CODE);
...
Các bạn có thể tạo file mới rồi chạy thử đoạn mã sau để xem các mã màu rồi lựa chọn cho phù hợp:
...
int main() {
HANDLE hConsole;
int k;
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
// you can loop k higher to see more color choices
for(k = 1; k < 255; k++) {
// pick the colorattribute k you want
SetConsoleTextAttribute(hConsole, k);
cout << k << " cstoigian@gmail.com " << endl;
}
cin.get(); // wait
return 0;
}
Và bây giờ chỉ cần cài đặt giải thuật tô màu cho option được focus là xong:
...
#define CLR_FOCUS 207
#define CLR_NORML 15
...
void printMenu(int focus, int len) {
clrscr();
int k;
HANDLE hConsole;
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
cout << "Draw Menu #" << ++count << endl;
cout << endl;
for (int i = 0; i < len; i++) {
if (i == focus) {
// set highlight color
SetConsoleTextAttribute(hConsole, CLR_FOCUS);
} else {
// reset color
SetConsoleTextAttribute(hConsole, CLR_NORML);
}
cout << i+1 << ". " << menu[i] << endl;
}
// reset color
SetConsoleTextAttribute(hConsole, CLR_NORML);
cout << endl;
cout << "focus=" << focus << "; len=" << len << endl;
}
...
Tiếp theo, cần phải cài đặt xử lý sự kiện cho các phím mũi tên Lên và Xuống khi được nhấn. Dễ thấy, khi nhấn phím xuống, focus sẽ tăng lên 1 và khi nhấn phím lên thì focus sẽ giảm đi 1. Đừng quên xử lý các trường hợp biên khi option đầu hoặc cuối đang được highlight.
Các phím mũi tên khi nhấn xuống sẽ nhận vào 2 giá trị kép là 224 (int) và một ký tự char. Do đó chúng ta cần phải xử lý điều kiện 2 lần đối với các trường hợp này.
...
do {
// Cac phim UP, DOWN, LEFT, RIGHT
// nhan vao gia tri kep
// la int 224 va char.
// Do do ta phai co 2 lan
// xu ly o day
int ch = getch();
if (ch == 0 || ch == 224) {
char c = getch();
switch(c) {
// UP
case 72:
if (focus == 0) {
focus = len - 1;
} else {
focus--;
}
break;
// DOWN
case 80:
if (focus == len - 1) {
focus = 0;
} else {
focus++;
}
break;
}
} else if (ch == 13){
// ENTER
if (focus == len - 1) {
exit(EXIT_SUCCESS);
}
}
printMenu(focus, len);
} while (true);
...
Đọc đến đây thì có lẽ các bạn đã có ý tưởng để hoàn tất menu này rồi phải không. Dù đây chưa phải là toàn bộ mã nguồn đầy đủ nhưng là những phần code chính yếu nhất của demo này. Nếu cần đầy đủ mã nguồn hoàn chỉnh để chạy thử trong Dev-C++, vui lòng kéo xuống cuối bài viết. Mã nguồn sẽ bao gồm: Mã bảng màu và Mã menu.