Acepto que el cursor parpadeante en un urwid.Button
parece un poco tonto, así que he encontrado una solución para ocultarlo. En urwid, el Button
la clase es solo una subclase de WidgetWrap
que contiene un SelectableIcon
y dos widgets de texto (los "<" y ">" adjuntos). Es el SelectableIcon
clase que establece la posición del cursor en el primer carácter de la etiqueta, de forma predeterminada. Subclasificando SelectableIcon
, modificando la posición del cursor y luego envolviéndolo en un urwid.WidgetWrap
subclase puede crear su propio botón personalizado que puede hacer todos los trucos de un Button
incorporado , o incluso más.
Esto es lo que parece en mi proyecto.
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)
A continuación, puede envolver un ButtonLabel
objeto junto con cualquier otro objeto en un WidgetWrap
subclase que será su clase de botón personalizado.
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
En este código, en realidad no hay mucha combinación de widgets en el FixedButton
WidgetWrap
subclase, pero podría agregar un "[
" y "]
" hasta los bordes del botón, envuélvelo en un LineBox
, etc. Si todo esto es superfluo, simplemente puede mover las funciones de manejo de eventos al ButtonLabel
clase, y hacer que emita una señal cuando se hace clic.
Para hacer que el botón se invierta cuando el usuario se mueve sobre él, envuélvelo en AttrMap
y establece el focus_map
a alguna entrada de paleta ("button_reversed
", en mi caso).
urwid usa la función curs_set, pero no la expone como un método de clase en ninguna parte. Alguien podría modificar urwid para permitir el uso de este método; de lo contrario, no existe un método confiable para hacerlo.
Puede reportarlo como un problema.
Sobre la base de la respuesta de Drunken Master, he limpiado la solución tanto como sea posible.
El urwid.SelectableIcon
es básicamente un urwid.Text
campo con este feo cursor parpadeante. Entonces, en lugar de anular el urwid.SelectableIcon
y empaquetarlo en un urwid.WidgetWrap
, tomemos un urwid.Text
directamente y hacerlo seleccionable y reaccionar a la activación del botón/ratón (inspirado en el sencillo tutorial de menú de 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()
Funciona de maravilla: