Linux 使用 ncurses 调整终端大小和滚动问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4738803/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 02:32:43  来源:igfitidea点击:

Resize terminal and scrolling problem with ncurses

clinuxncurses

提问by ubuntiano

I'm programming in C using ncurses libraries (it's the first time) and I've two problems. I'm on ubuntu with the default terminal (gnome terminal).

我正在使用 ncurses 库在 C 中编程(这是第一次),我有两个问题。我在 ubuntu 上使用默认终端(gnome 终端)。

1) I need to resize the terminal. I used resizeter() and resize_term(), but they fail.

1)我需要调整终端的大小。我使用了 resizeter() 和 resize_term(),但它们失败了。

2) I use scrollok() function and the problem is that I lose scrolled lines (when I get back with wscrl(), there are blank lines).

2)我使用 scrollok() 函数,问题是我丢失了滚动行(当我使用 wscrl() 返回时,有空行)。

#include <ncurses.h>

int main() {

WINDOW *win, *win2;

int i;
char c;

initscr();
cbreak();
noecho();

win=newwin(8,20,1,1);
box(win,0,0);
win2=newwin(6,18,2,2);
scrollok(win2,1);
wrefresh(win);
wrefresh(win);

for(i=0;i<15;i++){
    c=wgetch(win2);
    if(c=='u'){
        wscrl(win2,-1);
        wrefresh(win2);
    }
    else{
        wprintw(win2,"%c\n",c);
        wrefresh(win2);
    }
}

delwin(win);
delwin(win2);
endwin();

return 0;
}

回答by Fred Foo

  1. You can't resize the terminal window from ncurses. The functions you mention resize the part of the terminal window that is painted on by curses. The idea is you catch the SIGWINCHsignal and call resizetermin the handler when the user resizes the window from outside the application(using the mouse, probably).

  2. This is intended behavior, though poorly documented in ncurses and in the Unix standard/POSIX. NetBSD's curses docsstate it explicitly:

    If nis positive then stdscris scrolled up. nlines are lost from the top of stdscrand nblank lines are inserted at the bottom. If nis negative then stdscris scrolled down. nblank lines are inserted at the top of stdscrand nlines are lost from the bottom.

    So you'll have to manually save input and reprint it when scrolling.

  1. 您无法从 ncurses 调整终端窗口的大小。您提到的功能调整了由诅咒绘制的终端窗口部分的大小。这个想法是当用户从应用程序外部(可能使用鼠标)调整窗口大小时,您捕获SIGWINCH信号并调用resizeterm处理程序。

  2. 这是预期的行为,尽管在 ncurses 和 Unix 标准/POSIX 中记录很少。NetBSD 的 curses 文档明确指出:

    如果n为正,则stdscr向上滚动。 ñ线从顶部丢失stdscrÑ空白线被在底部插入。如果 n为负,则stdscr向下滚动。 Ñ空行被插入在顶部stdscrÑ线从底部丢失。

    因此,您必须手动保存输入并在滚动时重新打印。

回答by monty_oso

You can't resize the terminal window from ncurses but you can resize the terminal which the resizesystem call.

您不能从 ncurses 调整终端窗口的大小,但您可以调整调整大小系统调用的终端的大小

#include <ncurses.h>
#include <stdlib.h>

int main(int argc, char *argv[]){
    WINDOW *ventana1;
    system("resize -s 30 80");
    initscr();
    start_color();
    ventana1 = newwin(15, 50, 0, 0);
    init_pair(1,COLOR_YELLOW,COLOR_BLUE);
    init_pair(2,COLOR_BLUE, COLOR_YELLOW);
    wbkgd(ventana1,COLOR_PAIR(1));
    wprintw(ventana1, "POLLO");
    wrefresh(ventana1);
    wgetch(ventana1);
    wgetch(ventana1);
    system("resize -s 20 60");
    wbkgd(ventana1,COLOR_PAIR(2));
    wprintw(ventana1, "POLLO");
    wrefresh(ventana1);
    wgetch(ventana1);
    wgetch(ventana1);
    system("resize -s 35 85");
    system("clear");
    wbkgd(ventana1,COLOR_PAIR(1));
    wprintw(ventana1, "POLLO");
    wrefresh(ventana1);
    wgetch(ventana1);
    wgetch(ventana1);
    delwin(ventana1);
    endwin();
    system("resize -s 25 75");
}

回答by Thomas Dickey

POSIX does not cover this case, because the curses document is not part of POSIX. The Open Group happens to maintain documentation for both:

POSIX 不包括这种情况,因为curses 文档不是POSIX 的一部分。Open Group 碰巧维护以下两个方面的文档:

As noted in the manual page for resizeterm, you should not call that function from within a signal handler, because it calls "unsafe" functions. The topic of "unsafe" functions is discussed in several places; that in gcc's documentationwould do for a start.

如 的手册页所述resizeterm,您不应从信号处理程序中调用该函数,因为它调用了“不安全”的函数。“不安全”功能的话题在几个地方讨论过;在 gcc 的文档中可以作为一个开始。

Regarding documentation, @larsmans appears to be quoting from scroll(3), but not citing comparable links for ncurses and "POSIX". For what it's worth:

关于文档,@larsmans 似乎引用了scroll(3),但没有引用 ncurses 和“POSIX”的类似链接。物有所值:

  • ncurses(seems to address the points implied to be unique to NetBSD)
  • X/Open(is necessarily more general, as it is intended to cover different implementations)
  • ncurses(似乎解决了 NetBSD 独有的隐含点)
  • X/Open(必须更通用,因为它旨在涵盖不同的实现)

Back to OP's question:

回到OP的问题:

  1. the sample program does not show OP's use of resizetermnor of resize_term. It is not stated, but presumably OP resized the terminal window and the program did not respond. The manual page for resizetermis clear enough that ncurses does not cause the terminal to resize. For that(on some terminals), one can use the -soption of resize(a utility program for xterm). If successful, that resizes the terminal, which in turn sends a SIGWINCH. ncurses has a predefined signal handler for that, but at the applicationlevel, handling KEY_RESIZEis the recommended way. There are several programs in ncurses-exampleswhich do this.
  2. moving the lines upin a window necessarily moves some outof the window. That implies that lines are shifted intothe window to replacethose which have left. A "window" is just that: a limited-size view of data. For views with different size, the developer is advised to use "pads" (see manual page). The notes in the scroll manual page mention some issues with the color of blanks (the replacement lines). It is up to the application whether to leave the replacements blank or fill them with the application's data. Curses does not do that automatically (not even for pads).
  1. 示例程序没有显示 OPresizetermresize_term. 没有说明,但大概 OP 调整了终端窗口的大小并且程序没有响应。手册页resizeterm很清楚,ncurses 不会导致终端调整大小。对于(在某些终端),一个可以使用-s的选项resize(公用程序xterm)。如果成功,则会调整终端的大小,然后终端会发送一个SIGWINCH. ncurses 有一个预定义的信号处理程序,但在应用程序级别,处理KEY_RESIZE是推荐的方式。ncurses-examples 中有几个程序可以做到这一点。
  2. 在窗口中向上移动行必然会将一些移出窗口。这意味着,线转移该窗口替换那些已经离开。“窗口”就是这样:一个有限大小的数据视图。对于不同尺寸的视图,建议开发者使用“pads”(参见手册页)。滚动手册页中的注释提到了空白颜色(替换行)的一些问题。是将替换项留空还是用应用程序的数据填充它们取决于应用程序。Curses 不会自动执行此操作(即使对于打击垫也不行)。