问题描述
我正在编写一个ncurses
程序,并试图使其正确响应终端调整大小.虽然我可以在程序中正确读取端子尺寸,但ncurses
似乎无法正确处理新尺寸.这是一个(有些冗长)的示例程序:
I'm writing an ncurses
program and am trying to make it respond correctly to terminal resizing. While I can read the terminal dimensions correctly in my program, ncurses
doesn't seem to deal with new dimensions correctly. Here's a (somewhat lengthy) sample program:
#include <ncurses.h>
#include <string.h>
#include <signal.h>
#include <sys/ioctl.h>
void handle_winch(int sig){
struct winsize w;
ioctl(0, TIOCGWINSZ, &w);
COLS = w.ws_col;
LINES = w.ws_row;
wresize(stdscr, LINES, COLS);
clear();
mvprintw(0, 0, "COLS = %d, LINES = %d", COLS, LINES);
for (int i = 0; i < COLS; i++)
mvaddch(1, i, '*');
refresh();
}
int main(int argc, char *argv[]){
initscr();
struct sigaction sa;
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_handler = handle_winch;
sigaction(SIGWINCH, &sa, NULL);
while(getch() != 27) {}
endwin();
return 0;
}
如果运行它,可以看到正确检索了端子尺寸.但是第二行应该在屏幕上绘制*
字符,所以它不起作用.尝试水平调整窗口大小以使其更大,*
s的行将不会变大.
If you run it, you can see that the terminal dimensions are correctly retrieved. But the second line, which is supposed to draw *
-characters across the screen, doesn't work. Try resizing the window horizontally to make it larger, the line of *
s will not get larger.
这是什么问题?我知道有人可以暂时退出curses模式,但是我更喜欢一种更清洁的解决方案.谢谢!
What's the problem here? I'm aware that one can temporarily leave curses mode, but I'd prefer a cleaner solution. Thanks!
推荐答案
请勿设置COLS
和LINES
.这些由ncurses管理.同样,在调整大小后,让ncurses正确地重新初始化.这意味着不要调用wresize().只需调用endwin()即可.在使用其他ncurses函数之前,请确保在endwin()调用之后立即调用refresh().
Do not set COLS
and LINES
. These are managed by ncurses. Also, let ncurses reinitialize properly after a resize. That means, don't call wresize(). Just call endwin() instead. Make sure to call refresh() directly after an endwin() call before using other ncurses functions.
您也根本不需要ioctl(). ncurses负责自动检测新大小.
You also don't need the ioctl() at all. ncurses takes care of detecting the new size automatically.
所以您需要的几乎只是一个endwin()调用:
So what you need is pretty much just an endwin() call:
void handle_winch(int sig)
{
endwin();
// Needs to be called after an endwin() so ncurses will initialize
// itself with the new terminal dimensions.
refresh();
clear();
mvprintw(0, 0, "COLS = %d, LINES = %d", COLS, LINES);
for (int i = 0; i < COLS; i++)
mvaddch(1, i, '*');
refresh();
}
此外,某些ncurses版本被配置为提供自己的SIGWINCH处理程序.发生调整大小时,这些版本将KEY_RESIZE作为键输入返回.如果要利用它,则根本不需要信号处理程序.相反,您只需要:
Furthermore, some ncurses versions are configured to supply their own SIGWINCH handler. Those versions return KEY_RESIZE as a key input when a resize occurs. If you were to make use of that, you wouldn't need a signal handler at all. Instead, all you need is:
#include <ncurses.h>
#include <string.h>
int main()
{
initscr();
int key;
while ((key = getch()) != 27) {
if (key == KEY_RESIZE) {
clear();
mvprintw(0, 0, "COLS = %d, LINES = %d", COLS, LINES);
for (int i = 0; i < COLS; i++)
mvaddch(1, i, '*');
refresh();
}
}
endwin();
return 0;
}
不幸的是,您不能依赖于所有使用KEY_RESIZE配置的ncurses安装,因此信号处理程序是最可移植的解决方案.
Unfortunately, you can't rely on all ncurses installation being configured with KEY_RESIZE, so the signal handler is the most portable solution.
这篇关于用Ncurses调整故障大小?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!