【问题标题】:How do I determine the number of visible items in a listbox with urwid?如何使用 urwid 确定列表框中可见项目的数量?
【发布时间】:2018-02-11 22:23:08
【问题描述】:

当我向上或向下滚动 urwid.ListBox 中的可见项目列表时,我想实现一些提示,即是否还有项目低于或高于可见项目列表。 '向下滚动' 提示应该只在最后一个可见项目之后有剩余项目时出现,并且当最后一个可见项目是列表中的最后一个项目时它应该消失。反向适用于“向上滚动”提示。

然后我需要知道列表中有多少可见项目。有没有办法检索列表框中可见项目的数量,我想它等于列表框的高度,对吧?

这是我要检查的起点:

# This example is based on https://cmsdk.com/python/is-there-a-focus-changed-event-in-urwid.html
import urwid

def callback():
    index = str(listbox.get_focus()[1])
    debug.set_text("Index of selected item: " + index)

captions = "A B C D E F".split()
debug = urwid.Text("Debug")
items = [urwid.Button(caption) for caption in captions]
walker = urwid.SimpleListWalker(items)
listbox = urwid.ListBox(walker)
urwid.connect_signal(walker, "modified", callback)
frame = urwid.Frame(body=listbox, header=debug)
urwid.MainLoop(frame).run()

这个想法是要知道当终端窗口缩小或不够高以显示所有内容时,列表框是否在框架内完全可见,即frame.height >= listbox.height

【问题讨论】:

  • 您能否分享一个您已经尝试过的代码的最小示例?
  • @elias 没问题。完成。
  • 当我开始了解 urwid 的工作原理时,我希望在派生 ListBox 类之前无法解决这个问题,因为除非绘制组件,否则无法确定高度。大多数(如果不是全部)绘图方法都涉及大小参数,所以我想这就是交易,对吧?
  • 对,ListBox 有一个需要大小的calculate_visible 方法,所以我认为可以创建一个覆盖渲染方法的子类来调用它并设置一个属性来说明是否有项目不可见...我会尽快尝试 :)
  • 关于隐藏列表条目的可视化,我在this answer中描述了一个可能的解决方案。

标签: python listbox urwid


【解决方案1】:

因此,这是通过继承 urwid.ListBox 来实现此目的的一种方法,我们可以添加一个属性 all_children_visible,它在我们知道小部件的大小时设置(即在渲染或处理输入事件)。

示例代码,基于您提供的示例:

import string
import urwid

class MyListBox(urwid.ListBox):
    all_children_visible = True

    def keypress(self, size, *args, **kwargs):
        self.all_children_visible = self._compute_all_children_visible(size)
        return super(MyListBox, self).keypress(size, *args, **kwargs)

    def mouse_event(self, size, *args, **kwargs):
        self.all_children_visible = self._compute_all_children_visible(size)
        return super(MyListBox, self).mouse_event(size, *args, **kwargs)

    def render(self, size, *args, **kwargs):
        self.all_children_visible = self._compute_all_children_visible(size)
        return super(MyListBox, self).render(size, *args, **kwargs)

    def _compute_all_children_visible(self, size):
        n_total_widgets = len(self.body)
        middle, top, bottom = self.calculate_visible(size)
        n_visible = len(top[1]) + len(bottom[1])
        if middle:
            n_visible += 1
        return n_total_widgets == n_visible

def callback():
    debug.set_text(
        "Are all children visible? {}\n".format(listbox.all_children_visible)
    )


captions = list(string.uppercase + string.lowercase)

# uncomment this line to test case of all children visible:
# captions = list(string.uppercase)

debug = urwid.Text("Debug")
items = [urwid.Button(caption) for caption in captions]
walker = urwid.SimpleListWalker(items)
listbox = MyListBox(walker)
urwid.connect_signal(walker, "modified", callback)
frame = urwid.Frame(body=listbox, header=debug)
urwid.MainLoop(frame).run()

我不确定它的性能如何(我没有对它进行广泛的测试),所以我很好奇它在你的情况下会如何执行——让我知道它是如何进行的。 :)

【讨论】:

  • 非常感谢@elias。 “覆盖”render() 方法还不够吗?如果我没记错的话,从逻辑上讲,它应该由其他两个基类方法调用。
  • @Nasha 可能是的,但我认为尽早设置属性会很好,这样您就可以在已经知道事情是否合适的事件处理程序中挂钩更多逻辑,并且甚至在渲染之前就决定如何处理它——例如,您可能希望在 keypress 方法中调用回调。
  • 好的,我知道了。我的应用程序中可能不需要它。
  • @Nasha 顺便说一句,您能否让这种可见项目检查对您有用?
  • 我对这个话题有点分心,但我不会让这个话题出来。我会在确认后立即发布更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-04-01
  • 2019-02-24
  • 2011-08-20
  • 2011-05-28
  • 1970-01-01
  • 2017-09-10
  • 1970-01-01
相关资源
最近更新 更多