Python 使用 Curses 显示所有可用颜色对的问题

问题描述 投票:0回答:2

我正在运行 Python 3.10,并且遇到了诅咒问题,特别是在尝试利用全部颜色对时

curses.COLORS
返回
256

curses.COLOR_PAIRS
返回
65536

curses.has_extended_color_support()
返回
True

但是当我初始化 256、512、768、1024 等颜色对时...该颜色对似乎重置了初始化的颜色

此外,如果我尝试显示任何颜色对 > 255 (

curses.COLORS - 1
),它会使用其中一对 < 255 instead of the color pair ID I set. Curses allows me to run init_pair with these numbers, but it ignores them completely, and instead uses the color pair < 255

这是一个示例代码片段

#!/usr/bin/env python3.10

"""
Python3.10 added extended color support to curses
curses.COLOR_PAIRS (xterm-256color) returns 65,536
curses.COLORS (xterm-256color) returns 256
"""

import curses


def cycler(start_color, end_color):
    # cycle through all possible color IDs or pair IDs curses can display, loops indefinitely
    while True:
        for i in range(start_color, end_color):
            yield i


def main(stdscr):
    curses.start_color()
    height, width = stdscr.getmaxyx()

    RED = 1  # Reserve the red color at color ID 1
    curses.init_color(RED, 1000, 0, 0)

    color_cycler = cycler(2, curses.COLORS - 1)  # RED is reserved at 1, start at 2
    pair_cycler = cycler(1, curses.COLOR_PAIRS - 1)

    has_extended_support = curses.has_extended_color_support()
    stdscr.addstr(0, 0, f"COLORS:{curses.COLORS} "
                        f"COLOR_PAIRS:{curses.COLOR_PAIRS} "
                        f"ExtendedSupport:{has_extended_support}", curses.color_pair(1))

    for y in range(1, height - 1):
        for x in range(0, width, 5):

            color_id = next(color_cycler)
            pair_id = next(pair_cycler)

            intensity = int((color_id / (curses.COLORS - 1)) * 1000)
            curses.init_color(color_id, intensity, intensity, intensity)

            # create a new color pair, (RED) foreground, (color) background
            curses.init_pair(pair_id, RED, color_id)
            string = str(pair_id).rjust(5, ' ')
            stdscr.addstr(y, x, string, curses.color_pair(pair_id))

    stdscr.noutrefresh()
    curses.doupdate()
    stdscr.getch()


if __name__ == "__main__":
    curses.wrapper(main)

这是它为我生成的屏幕截图(注意数字 256、512、768、1024) 数字代表颜色对 ID

我尝试过的终端应用程序:

  • gnome 终端
  • 术语
  • 蒂尔达

大家都有同样的问题

python python-3.x ncurses curses python-curses
2个回答
2
投票

您必须使用 extended 接口,如 ncurses 6.1 的发布公告中所述:

进行此扩展的动机来自于注意到 termcap 应用程序可以(尽管不现实)使用比 16 位更大的数字,并且 256 色 xterm 的颜色对数量无法用terminfo(即 32767 与 65536)。此外,一些终端支持直接颜色,可以使用扩展。

Python 可能不会这样做(它的绑定仅覆盖 ncurses 的一部分),因此颜色值和颜色对是一个带符号的 16 位数字:

0..32767

现在... python 3.10 已于 2021 年 10 月发布。与颜色对相关的最新 ncurses 修复是在 2021 年 8 月。如果您使用旧版本的 ncurses(例如,通过在非常旧的东西上编译 python,例如 RHEL8),那么这只是一个已知的错误,答案将是“升级”。


0
投票

我创建了上述示例的 C++ 版本。不知道是否正确。

#include <ncurses.h>
#include <iterator>
#include <chrono>
#include <thread>

class Cycler
{
private:
    int startColor;
    int endColor;
    int current;

public:
    Cycler(int start, int end) : startColor(start), endColor(end), current(start) {}

    int next()
    {
        if (current >= endColor)
        {
            current = startColor;
        }
        return current++;
    }
};

int main()
{
    initscr();       // Initialize the window
    start_color();   // Start color functionality
    noecho();        // Do not echo any keypresses
    curs_set(FALSE); // Do not display a cursor

    int height, width;
    getmaxyx(stdscr, height, width);

    int RED = 1;                          // Reserve the red color at color ID 1
    init_extended_color(RED, 1000, 0, 0); // Initialize the red color

    Cycler colorCycler(2, COLORS - 1); // RED is reserved at 1, start at 2
    Cycler pairCycler(1, COLOR_PAIRS - 1);

    bool has_extended_support = has_colors() && can_change_color();
    attr_on(COLOR_PAIR(1), NULL);
    mvprintw(0, 0, "COLORS:%d COLOR_PAIRS:%d ExtendedSupport:%s", COLORS, COLOR_PAIRS, has_extended_support ? "True" : "False");
    attr_off(COLOR_PAIR(1), NULL);

    for (int y = 1; y < height - 1; ++y)
    {
        for (int x = 0; x < width; x += 5)
        {
            int color_id = colorCycler.next();
            int pair_id = pairCycler.next();

            int intensity = int((color_id / double(COLORS - 1)) * 1000);
            init_extended_color(color_id, intensity, intensity, intensity);

            // Create a new color pair, (RED) foreground, (color) background
            init_extended_pair(pair_id, RED, color_id);

            char str[6];
            attr_on(COLOR_PAIR(pair_id), NULL);
            mvprintw(y, x, "%5d", pair_id);
            attr_off(COLOR_PAIR(pair_id), NULL);
        }
    }

    refresh(); // Refresh the screen
    getch();   // Wait for a keypress
    endwin();  // End the window session

    return 0;
}

© www.soinside.com 2019 - 2024. All rights reserved.