ncurses 的字段中未显示更改
changes not showing in field in ncurses
我有一个 ncurses 程序,它是一个登录菜单,我使用字段作为用户名和密码。
问题是当我在字段中键入内容时,字符会注册但不会显示在终端中。换句话说,如果你执行代码 blow 并输入一些东西,你将无法在终端中看到它,但如果你按 F2,你可以看到这些字符已被注册。
这是我的代码:
test.cpp
#include <curses.h>
#include <form.h>
#include <menu.h>
#include <string>
#include <cstring>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
class WelcomeMenu {
private:
int _row; // number of rows of the terminal
int _col; // number of columns of the terminal
public:
WelcomeMenu();
~WelcomeMenu();
void welcomeBox();
void loginMenu();
void registerMenu();
};
WelcomeMenu::WelcomeMenu(){
initscr();
noecho();
cbreak();
keypad(stdscr, true);
int row, col;
getmaxyx(stdscr,row,col); /* get the number of rows and columns */
this->_row = row; this->_col = col;
loginMenu();
}
WelcomeMenu::~WelcomeMenu(){
refresh();
endwin();
}
/*
* This is useful because ncurses fill fields blanks with spaces.
*/
char* trim_whitespaces(char *str)
{
char *end;
// trim leading space
while(isspace(*str))
str++;
if(*str == 0) // all spaces?
return str;
// trim trailing space
end = str + strnlen(str, 128) - 1;
while(end > str && isspace(*end))
end--;
// write new null terminator
*(end+1) = '[=10=]';
return str;
}
void WelcomeMenu::loginMenu(){
// erase();
FORM *form;
FIELD *fields[5];
WINDOW *win_body, *win_form;
int ch;
win_body = newwin(24, 80, 0, 0);
assert(win_body != NULL);
box(win_body, 0, 0);
win_form = derwin(win_body, 20, 78, 3, 1);
assert(win_form != NULL);
box(win_form, 0, 0);
mvwprintw(win_body, 1, 2, "Press F1 to quit and F2 to print fields content");
fields[0] = new_field(1, 10, 0, 0, 0, 0);
fields[1] = new_field(1, 40, 0, 15, 0, 0);
fields[2] = new_field(1, 10, 2, 0, 0, 0);
fields[3] = new_field(1, 40, 2, 15, 0, 0);
fields[4] = NULL;
assert(fields[0] != NULL && fields[1] != NULL && fields[2] != NULL && fields[3] != NULL);
set_field_buffer(fields[0], 0, "Username: ");
set_field_buffer(fields[1], 0, "username");
set_field_buffer(fields[2], 0, "Password: ");
set_field_buffer(fields[3], 0, "password");
set_field_opts(fields[0], O_VISIBLE | O_PUBLIC | O_AUTOSKIP);
set_field_opts(fields[1], O_VISIBLE | O_PUBLIC | O_EDIT | O_ACTIVE);
set_field_opts(fields[2], O_VISIBLE | O_PUBLIC | O_AUTOSKIP);
set_field_opts(fields[3], O_VISIBLE | O_PUBLIC | O_EDIT | O_ACTIVE);
set_field_back(fields[1], A_UNDERLINE);
set_field_back(fields[3], A_UNDERLINE);
form = new_form(fields);
assert(form != NULL);
set_form_win(form, win_form);
set_form_sub(form, derwin(win_form, 18, 76, 1, 1));
post_form(form);
refresh();
wrefresh(win_body);
wrefresh(win_form);
while ((ch = getch()) != KEY_F(1)){
switch (ch) {
case KEY_F(2):
// Or the current field buffer won't be sync with what is displayed
form_driver(form, REQ_NEXT_FIELD);
form_driver(form, REQ_PREV_FIELD);
move(LINES-3, 2);
for (int i = 0; fields[i]; i++) {
printw("%s", trim_whitespaces(field_buffer(fields[i], 0)));
if (field_opts(fields[i]) & O_ACTIVE)
printw("\"\t");
else
printw(": \"");
}
refresh();
pos_form_cursor(form);
break;
case KEY_DOWN:
form_driver(form, REQ_NEXT_FIELD);
form_driver(form, REQ_END_LINE);
break;
case KEY_UP:
form_driver(form, REQ_PREV_FIELD);
form_driver(form, REQ_END_LINE);
break;
case KEY_LEFT:
form_driver(form, REQ_PREV_CHAR);
break;
case KEY_RIGHT:
form_driver(form, REQ_NEXT_CHAR);
break;
// Delete the char before cursor
case KEY_BACKSPACE:
case 127:
form_driver(form, REQ_DEL_PREV);
break;
// Delete the char under the cursor
case KEY_DC:
form_driver(form, REQ_DEL_CHAR);
break;
default:
form_driver(form, ch);
break;
}
}
wrefresh(win_form);
unpost_form(form);
free_form(form);
free_field(fields[0]);
free_field(fields[1]);
free_field(fields[2]);
free_field(fields[3]);
delwin(win_form);
delwin(win_body);
}
int main(){
WelcomeMenu * myConWin = new WelcomeMenu();
delete myConWin;
return 0;
}
你可以这样编译它:g++ -lncurses -lform test.cpp
提前感谢您的回复
您需要使用echo
和noecho
来打开回显on/off。如果您愿意,可以将该部分烘焙到输入函数中:
#include <memory>
struct input_context {
input_context() {
echo(); // echo typed characters
curs_set(1); // show the cursor
}
~input_context() {
curs_set(0); // hide the cursor
noecho(); // turn off echoing
}
};
std::string get_string(WINDOW* win, size_t len) {
std::unique_ptr<char[]> buf = std::make_unique<char[]>(len);
input_context dummy;
if(wgetnstr(win, buf.get(), len) != ERR) return std::string{buf.get()};
return {};
}
注意 1:当所有其他选项都用完时,您应该只使用 new
/delete
(和 new[]
/delete[]
)。在您的 main
中,您可以将 WelcomeMenu
的动态创建替换为自动变量:
int main(){
WelcomeMenu myConWin;
}
注2:使用nullptr
,不是NULL
。
fields[4] = nullptr; // was NULL
注意 3:正如@kebs 在评论中所述,您应该使用头文件的 C++ 版本:
#include <cassert> // was assert.h
#include <cstdio> // was stdio.h
#include <cstdlib> // was stdlib.h
该示例的基本问题是它没有提供显示字符的功能。在 ncurses 中,这将使用 form_driver
函数来完成:
form_driver
Once a form has been posted (displayed), you should funnel input events
to it through form_driver. This routine has three major input cases:
o The input is a form navigation request. Navigation request codes
are constants defined in <form.h>, which are distinct from the key-
and character codes returned by wgetch(3x).
o The input is a printable character. Printable characters (which
must be positive, less than 256) are checked according to the pro-
gram's locale settings.
o The input is the KEY_MOUSE special key associated with an mouse
event.
让您的程序使用 form_driver
将涉及对程序进行一些重组,将 switch 语句移动到可以从表单驱动程序调用的函数中。
ncurses 示例包括一些使用 form_driver
. You might want to read through the test-code, seeing how the basic loop
while (!finished) {
switch (form_driver(form, c = form_virtualize(form, w))) {
case E_OK:
MvAddStr(5, 57, field_buffer(secure, 1));
clrtoeol();
refresh();
break;
case E_UNKNOWN_COMMAND:
finished = my_form_driver(form, c);
break;
default:
beep();
break;
}
使用其 form_virtualize
函数来读取字符(或表单请求)。您(未)看到的可打印字符由 form_driver
处理,它会更新表单上的当前字段。您可以像 form_virtualize
中那样操作字段缓冲区并执行其他特殊操作,但是更新表单中的字段是您使用 form_driver
.[= 的原因22=]
我有一个 ncurses 程序,它是一个登录菜单,我使用字段作为用户名和密码。
问题是当我在字段中键入内容时,字符会注册但不会显示在终端中。换句话说,如果你执行代码 blow 并输入一些东西,你将无法在终端中看到它,但如果你按 F2,你可以看到这些字符已被注册。
这是我的代码:
test.cpp
#include <curses.h>
#include <form.h>
#include <menu.h>
#include <string>
#include <cstring>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
class WelcomeMenu {
private:
int _row; // number of rows of the terminal
int _col; // number of columns of the terminal
public:
WelcomeMenu();
~WelcomeMenu();
void welcomeBox();
void loginMenu();
void registerMenu();
};
WelcomeMenu::WelcomeMenu(){
initscr();
noecho();
cbreak();
keypad(stdscr, true);
int row, col;
getmaxyx(stdscr,row,col); /* get the number of rows and columns */
this->_row = row; this->_col = col;
loginMenu();
}
WelcomeMenu::~WelcomeMenu(){
refresh();
endwin();
}
/*
* This is useful because ncurses fill fields blanks with spaces.
*/
char* trim_whitespaces(char *str)
{
char *end;
// trim leading space
while(isspace(*str))
str++;
if(*str == 0) // all spaces?
return str;
// trim trailing space
end = str + strnlen(str, 128) - 1;
while(end > str && isspace(*end))
end--;
// write new null terminator
*(end+1) = '[=10=]';
return str;
}
void WelcomeMenu::loginMenu(){
// erase();
FORM *form;
FIELD *fields[5];
WINDOW *win_body, *win_form;
int ch;
win_body = newwin(24, 80, 0, 0);
assert(win_body != NULL);
box(win_body, 0, 0);
win_form = derwin(win_body, 20, 78, 3, 1);
assert(win_form != NULL);
box(win_form, 0, 0);
mvwprintw(win_body, 1, 2, "Press F1 to quit and F2 to print fields content");
fields[0] = new_field(1, 10, 0, 0, 0, 0);
fields[1] = new_field(1, 40, 0, 15, 0, 0);
fields[2] = new_field(1, 10, 2, 0, 0, 0);
fields[3] = new_field(1, 40, 2, 15, 0, 0);
fields[4] = NULL;
assert(fields[0] != NULL && fields[1] != NULL && fields[2] != NULL && fields[3] != NULL);
set_field_buffer(fields[0], 0, "Username: ");
set_field_buffer(fields[1], 0, "username");
set_field_buffer(fields[2], 0, "Password: ");
set_field_buffer(fields[3], 0, "password");
set_field_opts(fields[0], O_VISIBLE | O_PUBLIC | O_AUTOSKIP);
set_field_opts(fields[1], O_VISIBLE | O_PUBLIC | O_EDIT | O_ACTIVE);
set_field_opts(fields[2], O_VISIBLE | O_PUBLIC | O_AUTOSKIP);
set_field_opts(fields[3], O_VISIBLE | O_PUBLIC | O_EDIT | O_ACTIVE);
set_field_back(fields[1], A_UNDERLINE);
set_field_back(fields[3], A_UNDERLINE);
form = new_form(fields);
assert(form != NULL);
set_form_win(form, win_form);
set_form_sub(form, derwin(win_form, 18, 76, 1, 1));
post_form(form);
refresh();
wrefresh(win_body);
wrefresh(win_form);
while ((ch = getch()) != KEY_F(1)){
switch (ch) {
case KEY_F(2):
// Or the current field buffer won't be sync with what is displayed
form_driver(form, REQ_NEXT_FIELD);
form_driver(form, REQ_PREV_FIELD);
move(LINES-3, 2);
for (int i = 0; fields[i]; i++) {
printw("%s", trim_whitespaces(field_buffer(fields[i], 0)));
if (field_opts(fields[i]) & O_ACTIVE)
printw("\"\t");
else
printw(": \"");
}
refresh();
pos_form_cursor(form);
break;
case KEY_DOWN:
form_driver(form, REQ_NEXT_FIELD);
form_driver(form, REQ_END_LINE);
break;
case KEY_UP:
form_driver(form, REQ_PREV_FIELD);
form_driver(form, REQ_END_LINE);
break;
case KEY_LEFT:
form_driver(form, REQ_PREV_CHAR);
break;
case KEY_RIGHT:
form_driver(form, REQ_NEXT_CHAR);
break;
// Delete the char before cursor
case KEY_BACKSPACE:
case 127:
form_driver(form, REQ_DEL_PREV);
break;
// Delete the char under the cursor
case KEY_DC:
form_driver(form, REQ_DEL_CHAR);
break;
default:
form_driver(form, ch);
break;
}
}
wrefresh(win_form);
unpost_form(form);
free_form(form);
free_field(fields[0]);
free_field(fields[1]);
free_field(fields[2]);
free_field(fields[3]);
delwin(win_form);
delwin(win_body);
}
int main(){
WelcomeMenu * myConWin = new WelcomeMenu();
delete myConWin;
return 0;
}
你可以这样编译它:g++ -lncurses -lform test.cpp
提前感谢您的回复
您需要使用echo
和noecho
来打开回显on/off。如果您愿意,可以将该部分烘焙到输入函数中:
#include <memory>
struct input_context {
input_context() {
echo(); // echo typed characters
curs_set(1); // show the cursor
}
~input_context() {
curs_set(0); // hide the cursor
noecho(); // turn off echoing
}
};
std::string get_string(WINDOW* win, size_t len) {
std::unique_ptr<char[]> buf = std::make_unique<char[]>(len);
input_context dummy;
if(wgetnstr(win, buf.get(), len) != ERR) return std::string{buf.get()};
return {};
}
注意 1:当所有其他选项都用完时,您应该只使用 new
/delete
(和 new[]
/delete[]
)。在您的 main
中,您可以将 WelcomeMenu
的动态创建替换为自动变量:
int main(){
WelcomeMenu myConWin;
}
注2:使用nullptr
,不是NULL
。
fields[4] = nullptr; // was NULL
注意 3:正如@kebs 在评论中所述,您应该使用头文件的 C++ 版本:
#include <cassert> // was assert.h
#include <cstdio> // was stdio.h
#include <cstdlib> // was stdlib.h
该示例的基本问题是它没有提供显示字符的功能。在 ncurses 中,这将使用 form_driver
函数来完成:
form_driver
Once a form has been posted (displayed), you should funnel input events
to it through form_driver. This routine has three major input cases:
o The input is a form navigation request. Navigation request codes
are constants defined in <form.h>, which are distinct from the key-
and character codes returned by wgetch(3x).
o The input is a printable character. Printable characters (which
must be positive, less than 256) are checked according to the pro-
gram's locale settings.
o The input is the KEY_MOUSE special key associated with an mouse
event.
让您的程序使用 form_driver
将涉及对程序进行一些重组,将 switch 语句移动到可以从表单驱动程序调用的函数中。
ncurses 示例包括一些使用 form_driver
. You might want to read through the test-code, seeing how the basic loop
while (!finished) { switch (form_driver(form, c = form_virtualize(form, w))) { case E_OK: MvAddStr(5, 57, field_buffer(secure, 1)); clrtoeol(); refresh(); break; case E_UNKNOWN_COMMAND: finished = my_form_driver(form, c); break; default: beep(); break; }
使用其 form_virtualize
函数来读取字符(或表单请求)。您(未)看到的可打印字符由 form_driver
处理,它会更新表单上的当前字段。您可以像 form_virtualize
中那样操作字段缓冲区并执行其他特殊操作,但是更新表单中的字段是您使用 form_driver
.[= 的原因22=]