在 ncurses 中实现文本滚动的推荐方法是啥?

Posted

技术标签:

【中文标题】在 ncurses 中实现文本滚动的推荐方法是啥?【英文标题】:What is the recommended way to implement text scrolling in ncurses?在 ncurses 中实现文本滚动的推荐方法是什么? 【发布时间】:2011-10-18 06:42:22 【问题描述】:

我正在尝试实现一个文本滚动较少的 ncurses 应用程序。推荐的方法是什么?

这是我所知道的:

    您可以使用scroll 将文本缓冲区向上或向下移动1 行。但是,如果向下滚动,您最终会在顶部有一个空白行,如果向上滚动,则会在底部出现一个空白行,您必须自己重新绘制。 Ncurses 会为您自动换行,当我必须确定在步骤 1 中必须重新绘制哪一行时,这会弄乱我的数学。

我想我可以自己重新实现自动换行并保留所有后换行行的数组,但这似乎是一个常见问题,所以可能有更好的方法。

【问题讨论】:

用您使用的语言标记这个问题,以便可以看到问题。 ncurses 标签可能没那么流行。 来自linux.die.net/man/3/curs_scroll,好像还有scrl()的方法。这有什么不同的影响吗? sidyll: just did(node.js) 但我认为没有多少人在其中编写 curses 应用程序。 【参考方案1】:

答案取决于您拥有多少文本,以及您对屏幕上的数据有何其他用途。但通常pad 功能是显示可滚动文本的首选方式。这不仅是一个 ncurses 功能,而且受到大多数 curses 实现(即 1980 年代后期之后的任何东西)的支持。

pad就像一个窗口,但它的大小不限于当前屏幕大小。相反,数据通过一个视图显示,该视图在 pad 中的位置可以轻松更改。

ncurses-examples 中有两个相关的示例程序:view.c 通过将文件内容写入窗口来显示文件,而padview.c 使用在其上绘制整个文件的 pad,并使用 pad-根据需要向上/向下和向左/向右移动视图的功能。

在这些程序中,show_all 函数执行实际绘图,与 view.c(94 行)相比,padview.c(35 行)的长度大约是其三分之一。

进一步阅读:讨论 view 作为比较 ncurses 和 slang 库的示例。

【讨论】:

【参考方案2】:

我在 ncurses 方面还不是很有经验,所以我不知道所有的库函数,但是保持文本行的双向链接列表是可行的。这是 less 的原始克隆:

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

#define MAXLEN 128

typedef struct Line 
    char contents[MAXLEN];
    struct Line *prev, *next;
 Line;

Line *head, *curr;

int nr_lines;
int curr_line;

int term_rows, term_cols;

void load(const char *filename);
void draw(Line *l);

int main(int argc, char **argv)

    if (argc == 1)
    
        fputs("less: No file to open\n", stderr);
        return 1;
    

    initscr();
    noecho();
    keypad(stdscr, TRUE);   // for KEY_UP, KEY_DOWN
    getmaxyx(stdscr, term_rows, term_cols);
    addstr("Reading text...\n");

    load(argv[1]);

    curr = head;
    curr_line = 0;
    draw(curr);

    int ch;
    while ((ch = getch()) != EOF && ch != 'q')
    
        if (ch == KEY_UP && curr->prev != NULL)
        
            curr_line--;
            curr = curr->prev;
        
        else if (ch == KEY_DOWN && curr->next != NULL
            && curr_line + term_rows < nr_lines)
        
            curr_line++;
            curr = curr->next;
        
        draw(curr);
    

    endwin();
    return 0;


void load(const char *filename)

    FILE *fp = fopen(filename, "r");
    Line *lp;

    head = malloc(sizeof(Line));
    head->prev = head->next = NULL;
    curr = head;

    while (fgets(curr->contents, MAXLEN, fp))
    
        lp = malloc(sizeof(Line));
        lp->prev = curr;
        curr->next = lp;
        curr = lp;
        nr_lines++;
    
    curr->next = NULL;


void draw(Line *l)

    int i;
    clear();
    for (i = 0; i < term_rows && l != NULL; i++, l = l->next)
        addstr(l->contents);

我不确定这将如何处理超过 128 个字符的行,但使用不同的解决方案会产生不同的问题。

至于自动换行,如果您不需要保留原始文本格式,您可以在从文件中读取长行时将它们分成两段。

【讨论】:

【参考方案3】:

ncurses 只知道当前屏幕。当屏幕滚动时,ncurses 不会跟踪离开屏幕的任何文本。您的终端可能有一个回滚缓冲区,但它独立于 ncurses,并且 curses 无法看到终端的回滚缓冲区。

如果您需要滚动,我希望您需要跟踪文件中的当前位置。

我认为 ncurses 没有进行自动换行,你是如何进行自动换行的?

【讨论】:

以上是关于在 ncurses 中实现文本滚动的推荐方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

在 Objective-C 中实现这种滚动 UI 的最佳方式是啥?

在 QT 中实现具有多个小部件的视图的最佳方法是啥?

如何在 UITextView 中实现滚动功能?

在 ListView 的 header 中实现图像滚动

如何在 UITable 中实现 Instagram 评论的效果?

在 Java 中实现单例模式的有效方法是啥? [关闭]