Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/283.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何表明urwid列表框中的项目多于当前显示的项目?_Python_Listbox_Console Application_Urwid_Tui - Fatal编程技术网

Python 如何表明urwid列表框中的项目多于当前显示的项目?

Python 如何表明urwid列表框中的项目多于当前显示的项目?,python,listbox,console-application,urwid,tui,Python,Listbox,Console Application,Urwid,Tui,是否有方法向用户显示urwid列表框在显示部分的上方/下方有其他项 我在想一个类似滚动条的东西,它给出了条目数的概念 或列表框顶部/底部的单独栏 #!/usr/bin/env python3 # -*- coding: utf-8 -*- import urwid ENTRIES = [letter for letter in "abcdefghijklmnopqrstuvwxyz"] PALETTE = [ ("notifier_active", "dark cyan",

是否有方法向用户显示urwid列表框在显示部分的上方/下方有其他项

我在想一个类似滚动条的东西,它给出了条目数的概念

或列表框顶部/底部的单独栏

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import urwid

ENTRIES = [letter for letter in "abcdefghijklmnopqrstuvwxyz"]

PALETTE = [
    ("notifier_active",   "dark cyan",  "light gray"),
    ("notifier_inactive", "black", "dark gray"),
    ("reveal_focus",      "black",      "dark cyan", "standout")
]


class MyListBox(urwid.ListBox):
    def __init__(self, body, on_focus_change=None):
        super().__init__(body)

        self.on_focus_change = on_focus_change

    # Overriden
    def change_focus(self, size, position, offset_inset=0, coming_from=None, cursor_coords=None, snap_rows=None):
        super().change_focus(size,
                             position,
                             offset_inset,
                             coming_from,
                             cursor_coords,
                             snap_rows)

        # Implement a hook to be able to deposit additional logic
        if self.on_focus_change != None:
            self.on_focus_change(size,
                                 position,
                                 offset_inset,
                                 coming_from,
                                 cursor_coords,
                                 snap_rows)


class App(object):
    def __init__(self, entries):
        # Get terminal dimensions
        terminal_cols, terminal_rows = urwid.raw_display.Screen().get_cols_rows()
        list_rows = (terminal_rows - 2) if (terminal_rows > 7) else 5       
        # (available_rows - notifier_rows) OR my preferred minimum size

        # At the beginning, "top" is always visible
        self.notifier_top = urwid.AttrMap(urwid.Text('^', align="center"),
                                          "notifier_inactive")

        # Determine presentation depending on size and number of elements
        self.notifier_bottom = urwid.AttrMap(urwid.Text('v', align="center"),
                                             "notifier_inactive" if (len(entries) <= list_rows) else "notifier_active")

        contents = [urwid.AttrMap(urwid.Button(entry), "", "reveal_focus")
                    for entry in entries]

        self.listbox = MyListBox(urwid.SimpleFocusListWalker(contents),
                                 self.update_notifiers)                   # Pass the hook

        master_pile = urwid.Pile([
            self.notifier_top,
            urwid.BoxAdapter(self.listbox, list_rows),
            self.notifier_bottom,
        ])

        widget = urwid.Filler(master_pile,
                              'top')

        self.loop = urwid.MainLoop(widget,
                                   PALETTE,
                                   unhandled_input=self.handle_input)

    # Implementation for hook
    def update_notifiers(self, size, position, offset_inset, coming_from, cursor_coords, snap_rows):
        # which ends are visible? returns "top", "bottom", both or neither.
        result = self.listbox.ends_visible(size)

        if ("top" in result) and ("bottom" in result):
            self.notifier_top.set_attr_map({None:"notifier_inactive"})
            self.notifier_bottom.set_attr_map({None:"notifier_inactive"})
        elif "top" in result:
            self.notifier_top.set_attr_map({None:"notifier_inactive"})
            self.notifier_bottom.set_attr_map({None:"notifier_active"})
        elif "bottom" in result:
            self.notifier_top.set_attr_map({None:"notifier_active"})
            self.notifier_bottom.set_attr_map({None:"notifier_inactive"})
        else:
            self.notifier_top.set_attr_map({None:"notifier_active"})
            self.notifier_bottom.set_attr_map({None:"notifier_active"})

    def handle_input(self, key):
        if key in ('q', 'Q', 'esc'):
            self.exit()

    def start(self):
        self.loop.run()

    def exit(self):
        raise urwid.ExitMainLoop()


if __name__ == '__main__':
    app = App(ENTRIES)
    app.start()

如果无法实现此行为,有哪些方法实现此通知

在我的研究过程中,我发现,它试图最终实现同样的目标。
给出的答案似乎检查了所有元素是否都可见。不幸的是,如果由于终端未调整大小而在任何时候隐藏某些元素,则会失去其功能。

我想我已经找到了第二个可视化概念的实现(列表框顶部和底部的条形图)

唯一真正的区别是,我使用
SelectableRow
的实例,而不是
urwid.Button
。(
SelectableRow
取自。)

以下是相应的TUI:


我实现了一个列表框,默认情况下应用了第二个可视化概念(顶部和底部的条形图)

它被调用,可以通过安装


有关说明小部件功能的独立示例,请参阅

有关更多(和更简单的)示例,请参阅

有关参数和选项的详细说明,请参见



一些例子 最小的


在上面/下面显示项目


与其他小部件(也已设置样式)在contex中 在本例中,必须另外按下ctrl,以便列表框响应输入。
这允许在垂直容器中使用小部件(例如)


Niiiice!太棒了,我喜欢这个!谢谢分享!请参见,如中所述。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import urwid

HEADERS = ["column 1",
           "column 2",
           "column 3",
           "column 4"]

ENTRIES = [["{}1".format(letter),
            "{}2".format(letter),
            "{}3".format(letter),
            "{}4".format(letter)] for letter in "abcdefghijklmnopqrstuvwxyz"]

PALETTE = [
    ("column_headers", "white, bold", ""),
    ("notifier_active",   "dark cyan",  "light gray"),
    ("notifier_inactive", "black", "dark gray"),
    ("reveal_focus",      "black",      "dark cyan", "standout")
]


class SelectableRow(urwid.WidgetWrap):
    def __init__(self, contents, on_select=None):
        self.contents = contents
        self.on_select = on_select

        self._columns = urwid.Columns([urwid.Text(c) for c in contents])
        self._focusable_columns = urwid.AttrMap(self._columns, '', 'reveal_focus')

        super(SelectableRow, self).__init__(self._focusable_columns)

    def selectable(self):
        return True

    def update_contents(self, contents):
        # update the list record inplace...
        self.contents[:] = contents

        # ... and update the displayed items
        for t, (w, _) in zip(contents, self._columns.contents):
            w.set_text(t)

    def keypress(self, size, key):
        if self.on_select and key in ('enter',):
            self.on_select(self)
        return key

    def __repr__(self):
        return '%s(contents=%r)' % (self.__class__.__name__, self.contents)


class MyListBox(urwid.ListBox):
    def __init__(self, body, on_focus_change=None):
        super().__init__(body)

        self.on_focus_change = on_focus_change

    # Overriden
    def change_focus(self, size, position, offset_inset=0, coming_from=None, cursor_coords=None, snap_rows=None):
        super().change_focus(size,
                             position,
                             offset_inset,
                             coming_from,
                             cursor_coords,
                             snap_rows)

        # Implement a hook to be able to deposit additional logic
        if self.on_focus_change != None:
            self.on_focus_change(size,
                                 position,
                                 offset_inset,
                                 coming_from,
                                 cursor_coords,
                                 snap_rows)


class App(object):
    def __init__(self, entries):
        # Get terminal dimensions
        terminal_cols, terminal_rows = urwid.raw_display.Screen().get_cols_rows()
        list_rows = (terminal_rows - 6) if (terminal_rows > 11) else 5       
        # (available_rows - divider_rows - column_headers_row - notifier_rows) OR my preferred minimum size

        column_headers = urwid.AttrMap(urwid.Columns([urwid.Text(c) for c in HEADERS]),
                                       "column_headers")

        # At the beginning, "top" is always visible
        self.notifier_top = urwid.AttrMap(urwid.Text('^', align="center"),
                                          "notifier_inactive")

        # Determine presentation depending on size and number of elements
        self.notifier_bottom = urwid.AttrMap(urwid.Text('v', align="center"),
                                             "notifier_inactive" if (len(entries) <= list_rows) else "notifier_active")

        contents = [SelectableRow(entry) for entry in entries]

        self.listbox = MyListBox(urwid.SimpleFocusListWalker(contents),
                                 self.update_notifiers)                    # Pass the hook

        master_pile = urwid.Pile([
            urwid.Divider(u'─'),
            column_headers,
            urwid.Divider(u'─'),
            self.notifier_top,
            urwid.BoxAdapter(self.listbox, list_rows),
            self.notifier_bottom,
            urwid.Divider(u'─'),
        ])

        widget = urwid.Filler(master_pile,
                              'top')

        self.loop = urwid.MainLoop(widget,
                                   PALETTE,
                                   unhandled_input=self.handle_input)

    # Implementation for hook
    def update_notifiers(self, size, position, offset_inset, coming_from, cursor_coords, snap_rows):
        # which ends are visible? returns "top", "bottom", both or neither.
        result = self.listbox.ends_visible(size)

        if ("top" in result) and ("bottom" in result):
            self.notifier_top.set_attr_map({None:"notifier_inactive"})
            self.notifier_bottom.set_attr_map({None:"notifier_inactive"})
        elif "top" in result:
            self.notifier_top.set_attr_map({None:"notifier_inactive"})
            self.notifier_bottom.set_attr_map({None:"notifier_active"})
        elif "bottom" in result:
            self.notifier_top.set_attr_map({None:"notifier_active"})
            self.notifier_bottom.set_attr_map({None:"notifier_inactive"})
        else:
            self.notifier_top.set_attr_map({None:"notifier_active"})
            self.notifier_bottom.set_attr_map({None:"notifier_active"})

    def handle_input(self, key):
        if key in ('q', 'Q', 'esc'):
            self.exit()

    def start(self):
        self.loop.run()

    def exit(self):
        raise urwid.ExitMainLoop()


if __name__ == '__main__':
    app = App(ENTRIES)
    app.start()
#! /usr/bin/env python3
# -*- coding: utf-8 -*-

from additional_urwid_widgets import IndicativeListBox    # installed via pip
import urwid                                              # installed via pip

# Color schemes that specify the appearance off focus and on focus.
PALETTE = [("reveal_focus", "black", "light cyan", "standout")]

# The list box is filled with buttons.
body = [urwid.Button(letter) for letter in "abcdefghijklmnopqrstuvwxyz"]

# Wrap the list items into an 'urwid.AttrMap', so that they have an other appearance when focused.
# Instead of an simple list-like object you can/should create a 'urwid.ListWalker'.
attr_body = [urwid.AttrMap(entry, None, "reveal_focus") for entry in body]

ilb = IndicativeListBox(attr_body)

loop = urwid.MainLoop(ilb,
                      PALETTE)
loop.run()
#! /usr/bin/env python3
# -*- coding: utf-8 -*-

from additional_urwid_widgets import IndicativeListBox    # installed via pip
import urwid                                              # installed via pip

# Color schemes that specify the appearance off focus and on focus.
PALETTE = [("reveal_focus", "black", "light cyan", "standout")]

# The list box is filled with buttons.
body = [urwid.Button(letter) for letter in "abcdefghijklmnopqrstuvwxyz"]

# Wrap the list items into an 'urwid.AttrMap', so that they have an other appearance when focused.
# Instead of an simple list-like object you can/should create a 'urwid.ListWalker'.
attr_body = [urwid.AttrMap(entry, None, "reveal_focus") for entry in body]

ilb = IndicativeListBox(attr_body,
                        topBar_endCovered_prop=("{} above ...", None, None),
                        bottomBar_endCovered_prop=("{} below ...", None, None))

loop = urwid.MainLoop(ilb,
                      PALETTE)
loop.run()
#! /usr/bin/env python3
# -*- coding: utf-8 -*-

from additional_urwid_widgets import IndicativeListBox, MODIFIER_KEY    # installed via pip
import urwid                                                            # installed via pip

# Color schemes that specify the appearance off focus and on focus.
PALETTE = [("reveal_focus",              "black",            "light cyan",   "standout"),
           ("ilb_barActive_focus",       "dark cyan",        "light gray"),
           ("ilb_barActive_offFocus",    "light gray",       "dark gray"),
           ("ilb_barInactive_focus",     "light cyan",       "dark gray"),
           ("ilb_barInactive_offFocus",  "black",            "dark gray"),
           ("ilb_highlight_offFocus",    "black",            "dark cyan")]

# The list box is filled with buttons.
body = [urwid.Button(letter) for letter in "abcdefghijklmnopqrstuvwxyz"]

# Wrap the list items into an 'urwid.AttrMap', so that they have an other appearance when focused.
# Instead of an simple list-like object you can/should create a 'urwid.ListWalker'.
attr_body = [urwid.AttrMap(entry, None, "reveal_focus") for entry in body]

ilb = ilb = IndicativeListBox(attr_body,
                              modifier_key=MODIFIER_KEY.CTRL,
                              return_unused_navigation_input=False,
                              topBar_endCovered_prop=("ᐃ", "ilb_barActive_focus", "ilb_barActive_offFocus"),
                              topBar_endExposed_prop=("───", "ilb_barInactive_focus", "ilb_barInactive_offFocus"), 
                              bottomBar_endCovered_prop=("ᐁ", "ilb_barActive_focus", "ilb_barActive_offFocus"), 
                              bottomBar_endExposed_prop=("───", "ilb_barInactive_focus", "ilb_barInactive_offFocus"),
                              highlight_offFocus="ilb_highlight_offFocus")

pile = urwid.Pile([urwid.Text("The listbox responds only if 'ctrl' is pressed."),
                   urwid.Divider(" "),
                   urwid.Button("a button"),
                   urwid.BoxAdapter(ilb, 6),         # Wrap flow widget in box adapter
                   urwid.Button("another button")])


loop = urwid.MainLoop(urwid.Filler(pile, "top"),
                      PALETTE)
loop.run()