Souhlasím s tím, že blikající kurzor na urwid.Button
vypadá trochu chabě, takže jsem přišel s řešením, jak to skrýt. V urwid Button
class je pouze podtřídou WidgetWrap
obsahující SelectableIcon
a dva textové widgety (odvozující "<" a "">"). Je to SelectableIcon
třída, která ve výchozím nastavení nastaví pozici kurzoru na první znak štítku. Podtřídou SelectableIcon
, úpravou pozice kurzoru a jejím zabalením do urwid.WidgetWrap
podtřída si můžete vytvořit své vlastní tlačítko, které umí všechny triky a vestavěné Button
, nebo ještě více.
Tady je to, jak to vypadá v mém projektu.
import urwid
class ButtonLabel(urwid.SelectableIcon):
def __init__(self, text):
"""
Here's the trick:
we move the cursor out to the right of the label/text, so it doesn't show
"""
curs_pos = len(text) + 1
urwid.SelectableIcon.__init__(self, text, cursor_position=curs_pos)
Dále můžete zabalit ButtonLabel
objekt spolu s dalšími objekty do WidgetWrap
podtřída, která bude vaší vlastní třídou tlačítek.
class FixedButton(urwid.WidgetWrap):
_selectable = True
signals = ["click"]
def __init__(self, label):
self.label = ButtonLabel(label)
# you could combine the ButtonLabel object with other widgets here
display_widget = self.label
urwid.WidgetWrap.__init__(self, urwid.AttrMap(display_widget, None, focus_map="button_reversed"))
def keypress(self, size, key):
"""
catch all the keys you want to handle here
and emit the click signal along with any data
"""
pass
def set_label(self, new_label):
# we can set the label at run time, if necessary
self.label.set_text(str(new_label))
def mouse_event(self, size, event, button, col, row, focus):
"""
handle any mouse events here
and emit the click signal along with any data
"""
pass
V tomto kódu ve skutečnosti není mnoho kombinací widgetů v FixedButton
WidgetWrap
podtřídu, ale můžete přidat "[
“ a „]
" k okrajům tlačítka, zabalte jej do LineBox
atd. Pokud je toto vše zbytečné, můžete jednoduše přesunout funkce zpracování událostí do ButtonLabel
třídy a přimět jej, aby po kliknutí vydal signál.
Chcete-li, aby se tlačítko obrátilo, když na něj uživatel pohne, zabalte jej do AttrMap
a nastavte focus_map
na nějakou položku palety ("button_reversed
“, v mém případě).
urwid používá funkci curs_set, ale nikde ji nevystavuje jako metodu třídy. Někdo by mohl upravit urwid tak, aby umožňoval použití této metody; jinak neexistuje žádný spolehlivý způsob, jak to udělat.
Můžete to nahlásit jako problém.
Na základě odpovědi Drunken Master jsem vyčistil řešení, jak jen to bylo možné.
urwid.SelectableIcon
je v podstatě urwid.Text
pole s tímto ošklivým blikajícím kurzorem. Takže místo přepsání urwid.SelectableIcon
a zabalení do urwid.WidgetWrap
, vezměme urwid.Text
přímo a nastavte jej tak, aby bylo možné jej vybrat a reagovat na aktivaci tlačítka/myši (inspirováno jednoduchým výukovým programem nabídky urwid):
import urwid
choices = u'Chapman Cleese Gilliam Idle Jones Palin'.split()
class ListEntry(urwid.Text):
_selectable = True
signals = ["click"]
def keypress(self, size, key):
"""
Send 'click' signal on 'activate' command.
"""
if self._command_map[key] != urwid.ACTIVATE:
return key
self._emit('click')
def mouse_event(self, size, event, button, x, y, focus):
"""
Send 'click' signal on button 1 press.
"""
if button != 1 or not urwid.util.is_mouse_press(event):
return False
self._emit('click')
return True
def menu(title, choices):
body = [urwid.Text(title), urwid.Divider()]
for c in choices:
button = ListEntry(c)
urwid.connect_signal(button, 'click', item_chosen, c)
body.append(urwid.AttrMap(button, None, focus_map='reversed'))
return urwid.ListBox(urwid.SimpleFocusListWalker(body))
def item_chosen(button, choice):
response = urwid.Text([u'You chose ', choice, u'\n'])
done = ListEntry(u'Ok')
urwid.connect_signal(done, 'click', exit_program)
main.original_widget = urwid.Filler(urwid.Pile([response,
urwid.AttrMap(done, None, focus_map='reversed')]))
def exit_program(button):
raise urwid.ExitMainLoop()
main = urwid.Padding(menu(u'Pythons', choices), left=2, right=2)
top = urwid.Overlay(main, urwid.SolidFill(u'\N{MEDIUM SHADE}'),
align='center', width=('relative', 60),
valign='middle', height=('relative', 60),
min_width=20, min_height=9)
urwid.MainLoop(top, palette=[('reversed', 'standout', '')]).run()
Funguje jako kouzlo: