Spinbox text centering not working as intended/expected

I’m trying to create some spinboxes with centered text in the box. Looking at the docs at Spinbox (lv_spinbox) — LVGL documentation, it states that it’s a modified text area. Looking at the text area docs at Text area (lv_textarea) — LVGL documentation, it states that text alignment is to be set with lv_textarea_set_align(textarea, LV_TEXT_ALIGN_LEFT/RIGHT/CENTER). I’m able to use that setting with the supplied textarea example code, and center the text by adding lv.textarea.set_align(ta, lv.TEXT_ALIGN.CENTER) at the very end. Great, works as expected.

However, when trying to do the same with the spinbox, I add lv.spinbox.set_align(spinbox, lv.TEXT_ALIGN.CENTER) to the code (towards the front of the declaration/settings, or the end, no difference), but I throws the box to the top of the screen, left, right, or center (as declared), but the text within the box doesn’t shift relative to the textarea box.

What am I doing wrong here? This is on an M5Core2, using that board definition, on the latest, as of this morning, lv_micropython, commit #d22f6e6275be2b030b2678a2a871a5859e3e4ed2.

Code used on textarea (working fine):

def textarea_event_handler(e,ta):
    print("Enter was pressed. The current text is: " + ta.get_text())
    
def btnm_event_handler(e,ta):

    obj = e.get_target()
    txt = obj.get_btn_text(obj.get_selected_btn())
    if txt == lv.SYMBOL.BACKSPACE:
        ta.del_char()
    elif txt == lv.SYMBOL.NEW_LINE:
        lv.event_send(ta,lv.EVENT.READY,None)
    elif txt:
        ta.add_text(txt)

import lvgl as lv
lv.init()

from m5core2_power import Power
power = Power()

from ili9XXX import ili9341
lcd = ili9341(mosi=23, miso=38, clk=18, dc=15, cs=5, invert=True, rot=0x10, width=320, height=240, rst=-1, power=-1, backlight=-1)

from ft6x36 import ft6x36
touch = ft6x36(width=320, height=280)  

scr = lv.obj()
lv.scr_load(scr)


ta = lv.textarea(lv.scr_act())
ta.set_one_line(True)
ta.align(lv.ALIGN.TOP_MID, 0, 10)
ta.add_event_cb(lambda e: textarea_event_handler(e,ta), lv.EVENT.READY, None)
ta.add_state(lv.STATE.FOCUSED)   # To be sure the cursor is visible

btnm_map = ["1", "2", "3", "\n",
            "4", "5", "6", "\n",
            "7", "8", "9", "\n",
            lv.SYMBOL.BACKSPACE, "0", lv.SYMBOL.NEW_LINE, ""]
         
btnm = lv.btnmatrix(lv.scr_act())
btnm.set_size(200, 150)
btnm.align(lv.ALIGN.BOTTOM_MID, 0, -10)
btnm.add_event_cb(lambda e: btnm_event_handler(e,ta), lv.EVENT.VALUE_CHANGED, None)
btnm.clear_flag(lv.obj.FLAG.CLICK_FOCUSABLE)    # To keep the text area focused on button clicks
btnm.set_map(btnm_map)

lv.textarea.set_align(ta, lv.TEXT_ALIGN.CENTER)

Code used on spinbox (not working fine):

def increment_event_cb(e):
    code = e.get_code()
    if code == lv.EVENT.SHORT_CLICKED or code  == lv.EVENT.LONG_PRESSED_REPEAT:
        spinbox.increment()

def decrement_event_cb(e):
    code = e.get_code()
    if code == lv.EVENT.SHORT_CLICKED or code == lv.EVENT.LONG_PRESSED_REPEAT:
        spinbox.decrement()


import lvgl as lv
lv.init()

from m5core2_power import Power
power = Power()

from ili9XXX import ili9341
lcd = ili9341(mosi=23, miso=38, clk=18, dc=15, cs=5, invert=True, rot=0x10, width=320, height=240, rst=-1, power=-1, backlight=-1)

from ft6x36 import ft6x36
touch = ft6x36(width=320, height=280)  

scr = lv.obj()
lv.scr_load(scr)

spinbox = lv.spinbox(lv.scr_act())
spinbox.set_range(-1000, 25000)
spinbox.set_digit_format(5, 2)
spinbox.step_prev()
spinbox.set_width(100)
spinbox.center()

h = spinbox.get_height()

btn = lv.btn(lv.scr_act())
btn.set_size(h, h)
btn.align_to(spinbox, lv.ALIGN.OUT_RIGHT_MID, 5, 0)
btn.set_style_bg_img_src(lv.SYMBOL.PLUS, 0)
btn.add_event_cb(increment_event_cb, lv.EVENT.ALL,  None)

btn = lv.btn(lv.scr_act())
btn.set_size(h, h)
btn.align_to(spinbox, lv.ALIGN.OUT_LEFT_MID, -5, 0)
btn.set_style_bg_img_src(lv.SYMBOL.MINUS, 0)
btn.add_event_cb(decrement_event_cb, lv.EVENT.ALL, None)

lv.spinbox.set_align(spinbox, lv.TEXT_ALIGN.CENTER)

If I’m doing something wrong, please point me in the right direction. I didn’t see anything regarding text alignment in the spinbox docs, as there is in the textarea docs, so I’m figuring they’re meant to be more or less inheritied from the textarea settings. I’ve also tried lv.textbox.set_align(spinbox, lv.TEXT_ALIGN.CENTER), but that gives an error AttributeError: 'module' object has no attribute 'textbox'.

See How to align Text at the center with label.set_width() defined - #2 by amirgon

I think you should use set_style_text_align instead of set_align when using the lv.TEXT_ALIGN.* macros.

Thank you. I’m having little success there, it doesn’t seem to respond at all. This is with both spinbox.set_style_text_align(lv.TEXT_ALIGN.CENTER, 0) and spinbox.set_style_text_align(lv.ALIGN.CENTER, 0). No change when using something meant to give right hand alignment either (just looking for any sort of movement of the text, as one would see with the textarea settings). Is there another alignment argument I should be using? FWIW, it would seem the textarea docs caution against either of these, which is why I didn’t mention them in the initial message.

You are right.
But the following would work:

lv.textarea.set_align(spinbox, lv.TEXT_ALIGN.CENTER)

It actually calls the textarea implementation of set_align instead of the lv.obj one.

@kisvegabor - We discussed in the past whether Micropython inheritance should follow the new LVGL inheritance model or not, and agreed that the new inheritance model is only an internal thing and we can still inherit everything directly from lv.obj.
But it breaks here because Micropython selects lv_obj_set_align instead of lv_textarea_set_align when running spinbox.set_align, since spinbox inherits from lv.obj.

So in current situation we would need to define a new function lv_spinbox_set_align that calls lv_textarea_set_align. But really, why doesn’t set_style_text_align just work for both textarea and spinbox instead of adding new versions of “set_align” that change the meaning of lv_obj_set_align? It’s a little confusing in my opinion.

The lv.textarea.set_align fails, with the following:

>>> lv.textarea.set_align(spinbox, lv.TEXT_ALIGN.CENTER)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: argument has wrong type
>>>

Guessing the object type is what’s in contention there, but I’m not 100% on that.

Try this:

ta = lv.textarea.__cast__(spinbox)
ta.set_align(lv.TEXT_ALIGN.CENTER)

Thank you, definitely a marked improvement. Is there a way to make it vertically centered as well? I didn’t see such a setting for the textarea, so might not have one here.

@amirgon
I found a way to use the normal text_align style property so now it can be used on the spinbox too.
See https://github.com/lvgl/lvgl/commit/56ebb1a4c8cc988482ac9f118fa3c654553db941

1 Like

I suggest setting lv.SIZE_CONTENT height and adjusting the vertical padding.

@kisvegabor I don’t see where I’m to set the SIZE_CONTENT of it (it returns a value, but has two methods underneath, neither of which seem to be documented). That said, setting the style top pad was the trick, thank you.

Something like:

set_height(lv.SIZE.CONTENT)

Gotcha. I was looking to set the value of lv.SIZE.CONTENT, which wasn’t working. I did a cursory grep of “10193” from the git repo, didn’t see where/how that value is set, but I’m sure most would agree that value is a little outside the bounds. That said, setting the top pad, in addition to your previous suggestion/method with ta nailed it, thank you.

Ok, I’m able to work it out, but my C is weak (still learning it), and I’m really not familiar with the utility of it, other than backtracking to see I’m not using the large coordinates.

That said, the situation is solved for my purposes, in that I can make the system do what I’m wanting, so I’m willing to call this issue closed unless you or kisvegabor sees a need to delve into it further.

1 Like