- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
有没有办法向用户显示 urwid 列表框在显示部分的上方/下方有其他项目?
我正在考虑类似滚动条的东西,它可以显示条目的数量。
或列表框顶部/底部的单独栏。
如果这个行为不能实现,有什么方法可以实现这个通知?
在我的研究过程中,我发现了 this question ,它试图最终实现相同的目标。给定的答案似乎检查所有元素是否可见。不幸的是,如果某些元素在任何时候因为终端未调整大小而被隐藏,这将失去其功能。
最佳答案
我想我已经找到了第二个可视化概念的实现(列表框顶部和底部的栏)。
#!/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()
基本上,我创建了一个 urwid.Listbox
的子类,并覆盖了它的 change_focus()
方法以添加一个 Hook 。显然,这个方法是在焦点改变时在内部调用的。
实际逻辑使用 ends_visible()
方法的结果,该方法返回列表框当前可见的末端(顶部、底部、两者或两者都不)。基于此,我修改了两个周围 urwid.Text
元素的呈现。
代码生成以下 TUI:
我还编写了一个基于原始规范的代码变体:
#!/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()
唯一真正的区别是,我使用 SelectableRow
的实例而不是 urwid.Button
。 (SelectableRow
取自 this answer of user elias。)
这是对应的TUI:
关于python - 如何指示 urwid 列表框的项目多于当前显示的项目?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52428684/
尝试在 ListBox 顶部添加 BigText 时,我不断收到错误 AttributeError: 'BigText' object has no attribute 'rows'。我知道 BigT
在 urwid 中,如何动态更改调色板的颜色?例如,假设我想在按下“C”按钮时进行更改: import urwid def changeColor(key): if key in ('c',
我正在使用 urwid 设计一个 curses ui。我可以使用显示属性将文本显示为粗体、下划线或突出显示。是否可以使用斜体? 最佳答案 简答 理论上,是的。 在实践中:还没有。 长答案 基本上,cu
当用户按下 H 键时,我试图在我的 urwid 应用程序顶部显示一个帮助对话框,但我似乎无法让它消失。它显示没有问题。我错过了什么?我一整天都在做这件事。 我看过几个描述不同实现方法的例子。我玩过信号
我正在尝试使一个简单的 urwid 成为无限循环的输出屏幕。它需要输出来自另一个类的数据。 我现在找到的解决方案是:拥有一个带有 queue 属性的 Printer 类(实际输出类的测试替换器)。当它
我正在 urwid 中创建一个列表框,其中每个项目都是从 URL 列表中提取的 URL。当选择一个项目并单击 ENTER 时,我想提取 URL 并在浏览器中打开它。到目前为止,这是我的代码: clas
是否可以跟踪 urwid.ListBox 对象中高亮项的变化?或者甚至通过 ListWalker 对象? 我想在用户使用箭头键 [🠉]、[🠋] 从一个项目移动到另一个项目时调用回调,不是 当用户在
我正在使用 urwid,这是一个用于在 ncurses 中设计终端用户界面的 Python“框架”。不过有一件事我不能在 urwid 中做,而这在 curses 中很容易——使光标不可见。就像现在一样
我正在使用 urwid 库,到目前为止它非常棒。但我无法让进度条工作。我写了一个简单的测试程序,如下所示: import os import urwid # a function that t
我正在构建一个基于 Horizontal Menu 的应用程序来自 Urwid 的示例。我有一个项目,我想显示一些信息。我在下方有一个“确定”按钮,我希望它可以将菜单弹出回到之前的状态,或者重新启动整
有没有办法向用户显示 urwid 列表框在显示部分的上方/下方有其他项目? 我正在考虑类似滚动条的东西,它可以显示条目的数量。 或列表框顶部/底部的单独栏。 如果这个行为不能实现,有什么方法可以实现这
我正在用 Python 开发一个聊天程序,想为我的客户端添加一些用户友好的界面。事实是我给了自己挑战仅使用终端。 所以我找到了可以使用的 urwid 模块,它是跨平台的并且在网上有详细的文档。 看完模
我正在使用 Urwid 按钮,想知道是否有办法直接在按钮上处理按键事件? urwid.Button((item["customer"] + "/ " + item["case"]), button_p
我想实现一些提示,以确定当我向上或向下滚动时 urwid.ListBox 中的可见项目列表下方或上方是否仍有项目。仅当最后一个可见项目之后还有剩余项目时,“向下滚动”提示才应出现;当最后一个可见项目是
如果我进行以下调用: from urwid import raw_display cols, rows = raw_display.Screen().get_cols_rows() ... 文件描述符
我正在尝试编写一个具有不同 View 的程序。 我试图创建一个类来处理带有 urwid 的不同 View ,同时将 View 代码与其余部分分开。但经过多次不同的尝试,我不知道从哪里开始了。 我需要哪
与 urwid 混淆了。通过调整其中一个 urwid 示例,我得到了初始屏幕,并希望在按下 F5 键时执行 run_stuff() 函数,并显示指示 run_stuff() 正在运行并最终完成的消息(
我目前的权宜之计是将日志记录到一个文本文件中,但这不是很互动。我试过使用 pdb ,但这似乎与 urwid 不一致,pdb 一旦遇到断点就不会接受任何输入。 最佳答案 几个实践......调试 urw
是否可以将 ListBoxes 放入 SimpleListWalkers 中?我正在尝试制作嵌套的列表框,但出现此错误: AttributeError: 'MyListBox' 对象没有属性 'row
作为 Python 和 urwid 的新手,我尝试了这里的教程示例 http://excess.org/urwid/docs/tutorial/ 然而,虽然第一个确实工作正常,但大多数后来的似乎都不起
我是一名优秀的程序员,十分优秀!