Lv.style_plain not available?

OK, I’m clearly missing something here.
After doing some simple stuff like making buttons and labels etc. I decided to start using styles.
I thought I got the concept, but now I’m quite sure I don’t.

I copied the code to create a gauge. First from the examples directory, without style. This works perfectly.
But now this one. As soon as I run the program I get

AttributeError: 'module' object has no attribute 'style_plain'

And when i change to

style = lv.style_t()

I get:

AttributeError: 'lv_style_t' object has no attribute 'body'

So I tried typing help(lv.style_t), but then I see that this has only attributes with SET_ in front of it.
So the program is correct in stating that ‘style_plain’ is not an attribute, but where am I missing the point then?

import lvgl as lv
import lvesp32

# Import ILI9341 driver and initialize it

from ili9XXX import ili9341, LANDSCAPE

disp = ili9341(
    mosi=23, cs=22, clk=18, dc=2, rst=21,
    mhz=40,
    factor=16,
    hybrid=True,
    rot=LANDSCAPE,
    width=320,
    height=240
)

# Import XPT2046 driver and initialize it

from xpt2046 import xpt2046

touch = xpt2046(
    cs=14,
    transpose=False,
    cal_x0=3780,
    cal_y0=252,
    cal_x1=393,
    cal_y1=3751
)

style = lv.style_t(lv.style_plain)
style.body.main_color = lv.color_hex3(0x666)     # Line color at the beginning
style.body.grad_color =  lv.color_hex3(0x666)    # Line color at the end
style.body.padding.left = 10                     # Scale line length
style.body.padding.inner = 8                     # Scale label padding
style.body.border.color = lv.color_hex3(0x333)   # Needle middle circle color
style.line.width = 3
style.text.color = lv.color_hex3(0x333)
style.line.color = lv.color_hex3(0xF00)          # Line color after the critical value

# Describe the color for the needles
needle_colors = [
    lv.color_make(0x00, 0x00, 0xFF),
    lv.color_make(0xFF, 0xA5, 0x00),
    lv.color_make(0x80, 0x00, 0x80)
]

homescr = lv.obj()

# Create a gauge
gauge1 = lv.gauge(homescr)
gauge1.set_style(lv.gauge.STYLE.MAIN, style)
gauge1.set_needle_count(len(needle_colors), needle_colors)
gauge1.set_size(150, 150)
gauge1.align(None, lv.ALIGN.CENTER, 0, 20)

# Set the values
gauge1.set_value(0, 10)
gauge1.set_value(1, 20)
gauge1.set_value(2, 30)

# Load the screen

lv.scr_load(homescr)

@bvlet, I think you are mixing up LVGL v6 and v7.
Which version do you use?
Micropython is supported on both, but I recommend v7 if you are starting a new project.

There was a big change in styles between v6 and v7 in LVGL API.
v7 no longer has specific styles such as style_plain, and no body attribute of style_t.
Please have a look at Styles chapter on LVGL docs.

Instead, you can create a style (style = lv.style_t()), set its properties by calling its setter functions and then add this style (and possibly additional styles) to your objects.

You can see some examples of creating and using styles on advanced_demo.py, as well as more advanced topics such as creating a custom theme.

Hi @amirgon!
You were very right! I did not pay attention to the version selection in the top left on the lvgl site, and I was indeed working with a V6 example. I wasn’t aware that so much has changed between those two versions.
But: Now it works, written like this:

lv.init()

style = lv.style_t()

style.set_bg_color(lv.STATE.DEFAULT, lv.color_hex3(0x0F0))     # Line color at the beginning
style.set_bg_grad_color(lv.STATE.DEFAULT, lv.color_hex3(0x900))    # Line color at the end
style.set_border_color(lv.STATE.DEFAULT,lv.color_hex3(0xF00))   # Needle middle circle color
style.set_line_width(lv.STATE.DEFAULT, 2)
style.set_text_color(lv.STATE.DEFAULT, lv.color_hex3(0x333))
style.set_line_color(lv.STATE.DEFAULT, lv.color_hex3(0xF00))          # Line color after the critical value

# Describe the color for the needles
needle_colors = [
    lv.color_make(0x00, 0x00, 0xFF),
    lv.color_make(0x80, 0x00, 0x80)
]

homescr = lv.obj()

# Create a gauge
gauge1 = lv.gauge(homescr)
gauge1.set_range(0, 60)
gauge1.set_scale(230, 31, 7)
gauge1.set_needle_count(len(needle_colors), needle_colors)
gauge1.set_size(200, 200)
gauge1.align(None, lv.ALIGN.CENTER, 0, -20)
gauge1.set_critical_value(40)
# Set the values
gauge1.set_value(1, 50)

# Load the screen
for number in range(1, 61):
    gauge1.set_value(1, number)
    lv.scr_load(homescr)

The only thing I didn’t really get is why

gauge1.set_size(200, 200)

works, when set_size is not an attribute of lv.gauge() according to the help function…

Now I can start looking into some real world applications. In the way I coded it now it’s not the fastest needle I’ve ever seen :slight_smile:

Thank you for your support!

That’s because all widgets are descendants of lv_obj. You can call any lv_obj function on every widget (although some of them override default behavior)

This is because the C and MicroPython APIs use different inheritance semantics. Right now, in C, everything is implemented using global functions, not function pointers on a structure, meaning that descendant objects generally don’t have parent functions declared. You are forced to memorize or look up the inheritance chain to know what methods are safe to call on what objects.

In MicroPython @amirgon worked around this by having the binding autogenerate parent functions on descendant objects, thus you get more natural behavior there.

If we were using C++ they would behave the same way, but that’s another story… :slightly_smiling_face:

1 Like