在 ncurses 中移动 windows

Moving windows in ncurses

我已经阅读了 window(3NCURSES) 手册页,但我无法完全理解 mvwin() 函数的实际作用以及它的子 windows.

会发生什么

下面的代码创建了一个带有标题 "Window" 和边框的 window,它还创建了一个子 window 用于打印 y,x 位置而不破坏 parent window边框。然后它将 parent window 移动到一个新位置,但结果不是我所期望的:

  1. 移动window后,原位置windows边框+文字的轮廓不会自动擦除。

  2. 移动后,将文本写入子window,在新旧位置输出。

  3. 移动后parentwindow有了新的y,x坐标,但是subwindow还是显示旧坐标

我对 ncurses 没有太多经验,也许我遗漏了什么,但这种行为是完全不合逻辑的。如果我必须在旧位置手动擦除 windows 并手动移动所有子 windows,那么这首先抵消了使用 ncurses 的好处。我期待 ncurses 自动处理这些 low-level 细节。

我对 subwindows 的理解是它们用于将一个大的 window 划分为较小的 non-overlapping 区域。所以当 parent window 被移动或刷新时,它的所有子 windows 应该被自动移动或刷新。这是正确的吗?

#include <assert.h>
#include <ncurses.h>
#include <unistd.h>

int main()
{
    WINDOW *win, *swin;
    int lines, cols, y, x;

    initscr();
    keypad(stdscr, TRUE);
    noecho();

    // Create window
    lines = 10; cols  = 40;
    y = 5; x = 5;
    win = newwin(lines, cols, y, x);
    assert(win != NULL);

    // Create window border
    box(win, 0, 0);
    mvwprintw(win, 0, 2, " Window ");

    // Create subwindow
    swin = subwin(win, lines-2, cols-2, y+1, x+1);
    assert(swin != NULL);
    // Print window and subwindow y,x
    mvwprintw(swin, 0, 0, "win y,x=%d,%d  swin y,x=%d,%d\n",
        getbegy(win), getbegx(win), getbegy(swin), getbegx(swin));

    // Refresh
    wnoutrefresh(stdscr);
    wnoutrefresh(win);
    wnoutrefresh(swin);
    doupdate();

    sleep(2);

    // Move window
    y = 20; x = 40;
    mvwin(win, y, x);
    mvwprintw(swin, 0, 0, "win y,x=%d,%d  swin y,x=%d,%d\n",
        getbegy(win), getbegx(win), getbegy(swin), getbegx(swin));

    // Refresh
    wnoutrefresh(stdscr);
    wnoutrefresh(win);
    wnoutrefresh(swin);
    doupdate();

    wgetch(swin);

    endwin();
    return 0;
}

显然不是:对 Solaris 10 的快速检查给出了相同的行为。您可能会发现某些情况下 ncurses 无意中有所不同,但这不是其中之一。 FAQ 提出了关于兼容性的观点:

extensions (deviations from SVr4 curses) are allowed only if they do not modify the documented/observed behavior of the API.

Solaris manual page 没有说清楚,因为唯一提到的子窗口是关于移动 它们:

The mvwin() routine moves the window so that the upper left-hand corner is at position (x, y). If the move would cause the window to be off the screen, it is an error and the window is not moved. Moving subwindows is allowed, but should be avoided.

Solaris source code tells the story for that: it does nothing with subwindows. Some retesting a while back (early 2006) in response to a user's comment about differences pointed out that ncurses was incorrectly attempting to copy subwindows. That part is ifdef'd out(因为它太有趣了,不能删除)。由于 mvwin 没有太多事情要做,实际代码非常相似。

X/Open 对 mvwin 的描述过于简短和模糊,没有任何用处。