Trong bài hôm nay chúng ta sẽ add thêm hành động vào Menu, khi được lựa chọn, chương trình sẽ tạo ra một form nhập dữ liệu.
Chúng ta đã biết rằng một ứng dụng NCurses có thể sử dụng màu hoặc không. Vậy có thể thay đổi các màu hiển thị không? Tất nhiên là được.
Chúng ta cùng tham khảo file cursesapp.cc trong folder c++:
Root_Window->setcolor(1); Root_Window->setpalette(COLOR_YELLOW,COLOR_BLUE); Root_Window->setcolor(2); Root_Window->setpalette(COLOR_CYAN,COLOR_BLUE); Root_Window->setcolor(3); Root_Window->setpalette(COLOR_BLACK,COLOR_BLUE); Root_Window->setcolor(4); Root_Window->setpalette(COLOR_BLACK,COLOR_CYAN); Root_Window->setcolor(5); Root_Window->setpalette(COLOR_BLUE,COLOR_YELLOW); Root_Window->setcolor(6); Root_Window->setpalette(COLOR_BLACK,COLOR_GREEN); |
Để cài đặt thuộc tính Color, bạn sử dụng một Color Pair trong NCurses, tức một thuộc tính màu gồm 2 màu đi với nhau đó là foreground color và background color.
Chương trình của chúng ta có 6 thuộc tính màu (6 color pair). Để biết được 6 color pair này được dùng như thế nào thì chúng ta có thể đọc ở file cursesapp.h:
// Attributes to use for menu and forms foregrounds virtual chtype foregrounds() const { return b_Colors ? static_cast<chtype>(COLOR_PAIR(1)) : A_BOLD; } // Attributes to use for menu and forms backgrounds virtual chtype backgrounds() const { return b_Colors ? static_cast<chtype>(COLOR_PAIR(2)) : A_NORMAL; } // Attributes to use for inactive (menu) elements virtual chtype inactives() const { return b_Colors ? static_cast<chtype>(COLOR_PAIR(3)|A_DIM) : A_DIM; } // Attributes to use for (form) labels and SLKs virtual chtype labels() const { return b_Colors ? static_cast<chtype>(COLOR_PAIR(4)) : A_NORMAL; } // Attributes to use for form backgrounds virtual chtype dialog_backgrounds() const { return b_Colors ? static_cast<chtype>(COLOR_PAIR(4)) : A_NORMAL; } // Attributes to use as default for (form) window backgrounds virtual chtype window_backgrounds() const { return b_Colors ? static_cast<chtype>(COLOR_PAIR(5)) : A_NORMAL; } // Attributes to use for the title window virtual chtype screen_titles() const { return b_Colors ? static_cast<chtype>(COLOR_PAIR(6)) : A_BOLD; } |
Để thực thi một hành động khi một Menu Item được người dùng chọn, đầu tiên chúng ta sẽ tạo ra một class thừa kế NcursesMenuItem và implement hàm action().
Ở đây ta sẽ thử một action đơn giản: Quit
class QuitItem : public NCursesMenuItem { public: QuitItem() : NCursesMenuItem("Quit") { } // giá trị trả về của hàm action: // trả về true để thoát menu // trả về false sẽ mở lại menu virtual bool action() { return true; } }; |
Và trong hàm khởi tạo Menu chúng ta sửa Item cuối cùng:
items[5] = new QuitItem(); |
Bạn hãy biên dịch và chạy thử, khi lựa chọn Quit, menu duy nhất của chương trình được đóng, nên chương trình của chúng ta sẽ kết thúc.
Trong phần này, chúng ta sẽ tạo ra một form nhập dữ liệu, và các dữ liệu sẽ dược validate khi nhập, ví dụ như bạn sẽ đặt giới hạn cho một số nguyên, NCurses sẽ kiểm tra dữ liệu bạn vừa nhập vào có nằm trong giới hạn không thì mới cho phép nhập sang Field khác, hoặc kiểu Enumeration sẽ chỉ cho phép người dùng nhập một trong các giá trị bạn đã định sẵn. Đầu tiên chúng ta sẽ thử tạo một Form cơ bản: Tạo ra một class NCursesFormLabel làm tiêu đề cho field, thực chất đây là một NcursesFormField bị tắt đi các thuộc tính Edit và Active.
#include <cursesf.h> // curses form class NCursesFormLabel : public NCursesFormField { public: NCursesFormLabel(const char* title, int row, int col) : // 2 thuộc tính đầu là size, số dòng và số cột mà title này chiếm // 2 tham số sau là vị trí NCursesFormField(1, std::strlen(title), row, col) { set_value(title); // tắt tính năng edit và thuộc tính active options_off(O_EDIT | O_ACTIVE); } }; |
Chúng ta bắt đầu tạo một form.
class MyForm : public NCursesForm { private: NCursesFormField** fields; public: MyForm() : NCursesForm(5, 50, (lines()-15)/2, (cols()-50)/2), fields(NULL) { fields = new NCursesFormField*[2]; fields[0] = new NCursesFormLabel("NCurses Form Demo", 0, 15); fields[1] = new NCursesFormField(); InitForm(fields, true, true); boldframe(); } }; |
Tiếp theo là FormAction.
class FormAction : public NCursesMenuItem { public: FormAction(const char* title) : NCursesMenuItem(title) { } virtual bool action() { MyForm form; form(); return false; } }; |
Và thay đổi menu item của chúng ta.
items[0] = new FormAction("Form Demo"); items[1] = new NCursesMenuItem("Item 2"); items[2] = new NCursesMenuItem("Item 3"); items[3] = new NCursesMenuItem("Item 4"); items[4] = new NCursesMenuItem("Item 5"); items[5] = new QuitItem(); items[6] = new NcursesMenuItem(); |
Khi khởi chạy, chương trình hiển thị như sau:
Nếu bấm Ctrl X để thoát khỏi Form, chương trình sẽ trở lại menu chính.
Ở phần trên form của chúng ta chỉ gồm có tiêu đề, giờ ta sẽ add thêm field để cho người dùng nhập.
Bạn tạo ra một field.
MyForm() : NCursesForm(7, 50, (lines()-15)/2, (cols()-50)/2), fields(NULL), intField(NULL) { fields = new NCursesFormField*[4]; fields[0] = new NCursesFormLabel("NCurses Form Demo", 0, 15); // cùng nằm trên dòng 2, fields[2] lùi lại phia sau fields[1] = new NCursesFormLabel("Input a number", 2, 3); fields[2] = new NCursesFormField(1, 10, 2, 30); fields[3] = new NCursesFormField(); InitForm(fields, true, true); boldframe(); } |
Giờ chúng ta sẽ thêm type vào cho field để giới hạn nội dung nhập.
Mình sẽ tạo thêm 1 field không có limit để dễ so sánh.
class MyForm : public NCursesForm { private: NCursesFormField** fields; Integer_Field* intField; public: MyForm() : NCursesForm(10, 50, (lines()-15)/2, (cols()-50)/2), fields(NULL), intField(NULL) { fields = new NCursesFormField*[6]; fields[0] = new NCursesFormLabel("NCurses Form Demo", 0, 15); // cùng nằm trên dòng 2, fields[2] lùi lại phia sau fields[1] = new NCursesFormLabel("Input a number between 1-10", 2, 3); fields[2] = new NCursesFormField(1, 10, 2, 32); fields[3] = new NCursesFormLabel("Input a number", 4, 3); fields[4] = new NCursesFormField(1, 10, 4, 32); fields[5] = new NCursesFormField(); intField = new Integer_Field(0, 1, 10); fields[2]->set_fieldtype(*intField); InitForm(fields, true, true); boldframe(); } ~MyForm() { delete intField; } }; |
Nếu bạn không nhập đúng ở Field đầu tiên, bạn sẽ không thể bấm Enter để chuyển sang Field tiếp theo, hãy thử nhập vài lần để chắc chắn Field Type đã hoạt động.
(Xóa ký tự bằng Ctrl + H, có thể code để sửa thành Backspace cho tiện – vấn đề này sẽ ở một bài khác)
Manh
December 22, 2015
C++