我正在探索基于 ncurses 窗口教程的修改程序来移动窗口,而无需每次使用
mvwin
删除和重新制作它,并且遇到了以下问题:
erase
(代码中的注释 1)清除旧字符,或者在每行开头打印换行符。查看 docs,这看起来像是调用 touchwin
/touchline
应该可以解决的问题,但事实并非如此。 第一个问题:如果不是这样,touchwin
会做什么?redrawwin
强制显示移动的窗口,但唯一有效的是在擦除屏幕后立即添加另一个刷新(代码中的注释 2)。我不喜欢这种方法,它会导致屏幕闪烁,感觉必须有更好的方法。 第二个问题:有没有办法在擦除屏幕后显示移动窗口而无需再次刷新?refresh
将仅显示写入的行,而不显示移动的窗口,但调用wrefresh(my_win)
将显示移动的窗口和打印的行。 第三个问题:为什么wrefresh
显示刷新窗口之外的东西?示例代码:
int main()
{ WINDOW *my_win;
int startx, starty, width, height;
int ch, err;
initscr();
cbreak();
keypad(stdscr, TRUE);
height = 3;
width = 10;
starty = (LINES - height) / 2;
startx = (COLS - width) / 2;
refresh();
my_win = create_newwin(height, width, starty, startx);
while((ch = getch()) != KEY_F(4))
{
erase(); // <--(1)
refresh(); // <--(2)
switch(ch)
{
case KEY_LEFT:
mvprintw(0, 0, "moving window to position (%d, %d)", starty, --startx);
err = mvwin(my_win, starty, startx);
break;
case KEY_RIGHT:
mvprintw(0, 0, "moving window to position (%d, %d)", starty, ++startx);
err = mvwin(my_win, starty, startx);
break;
case KEY_UP:
mvprintw(0, 0, "moving window to position (%d, %d)", --starty, startx);
err = mvwin(my_win, starty, startx);
break;
case KEY_DOWN:
mvprintw(0, 0, "moving window to position (%d, %d)", ++starty, startx);
err = mvwin(my_win, starty, startx);
break;
default:
mvprintw(0, 0, "UNKNOWN INPUT!");
}
if (err != NCURSES_OK)
{
mvprintw(0, 0, "Error %d while moving window", err);
}
wrefresh(my_win); // <--(3)
}
endwin();
return 0;
}
例如将窗口向左移动两次后的“剩余字符”:
moving window to position (6, 32)
┌────────┐┐┐
│ │││
└────────┘┘┘
在 (n)curses 中,刷新意味着将与给定窗口关联的数据绘制到物理屏幕1。作为优化,已经标记为绘制的数据将不会再次绘制。
使用新数据更新窗口中的位置会删除该位置上的任何标记。
erase
(werase
) 用空白更新窗口中的每个位置(删除所有标记)。
touchwin
(touchline
) 强制删除关联窗口内的每个标记,而不更改任何数据,以便下次 刷新 时重新绘制所有内容。
mvwin(my_win, ...)
和wrefresh(my_win);
更改与my_win
相关的数据,并将其绘制到物理屏幕上。 stdscr
不知道发生了这种情况,并且不知道重新绘制先前已标记为已绘制的另一个窗口“后面”的位置。这就是为什么您必须以某种方式删除这些标记。
wrefresh(my_win);
不会刷新 my_win
和 stdscr
,而是因为 getch
(更新)而执行
refresh
。
来自:如果窗口不是 pad,并且自上次调用
wrefresh顺序以来已移动或修改过,则将在读取另一个字符之前调用 wrefresh。
请注意,所有这些交互在很大程度上取决于调用函数的
。典型的顺序是:
(可选)擦除/清除/触摸窗口刷新
getch(3)
stdscr
,第一次迭代后)擦除getch
stdscr
stdscr
stdcr
my_win
my_win
的阻塞性质以及它刷新标准窗口的事实,使您能够实际
看到由
getch
生成的行(否则您有一个更新 - >擦除对于mvprintw
)。
这是一个重构的示例:stdscr
#include <ncurses.h>
#define clearline(y) do { move(y, 0); clrtoeol(); } while (0)
int main(void)
{
initscr();
cbreak();
keypad(stdscr, TRUE);
curs_set(0);
const int height = 3;
const int width = 10;
int y = (LINES - height) / 2;
int x = (COLS - width) / 2;
WINDOW *my_win = newwin(height, width, y, x);
box(my_win, 0, 0);
mvwaddstr(my_win, 1, 2, "Hello!");
while (1) {
/* draw our background, then our boxed window */
refresh();
wrefresh(my_win);
int ch = getch();
/* touch the 'background' lines behind our boxed window,
* AFTER `getch` would have redrawn, but BEFORE updating `y` */
touchline(stdscr, y, height);
switch (ch) {
case KEY_UP: --y; break;
case KEY_DOWN: ++y; break;
case KEY_LEFT: --x; break;
case KEY_RIGHT: ++x; break;
default:
}
if ('q' == ch || ERR == ch)
break;
/* `touchline` above, and this `clearline` are a small optimization over
* just calling `erase()` right here */
clearline(0);
mvprintw(0, 0, "moving window to position (%d, %d)", y, x);
if (OK != mvwin(my_win, y, x))
mvprintw(1, 0, "Error moving window <%p>", (void *) my_win);
else
clearline(1);
}
delwin(my_win);
endwin();
}
moving window to position (3, 34)
┌────────┐
│ Hello! │
└────────┘
。2。
稍后刷新将覆盖由早期刷新绘制的任何数据,这会在物理屏幕上发生冲突。