kdschlosser / lv_cpython

CPython bindings to LVGL
Other
16 stars 4 forks source link

how to get text? #9

Open fbiego opened 1 year ago

fbiego commented 1 year ago

using text = lv.label_get_text(ui_text)

gives the error below

    instance._obj = value.encode('utf-8')
                    ^^^^^^^^^^^^
AttributeError: cdata 'char *' has no attribute 'encode'
kdschlosser commented 1 year ago

an entire traceback would help so I know what line number that code is on. The entire binding is automatically generated so unless I know exactly where in the generated file that code is it going to be hard to locate where in the generation script needs to be changed.

fbiego commented 1 year ago
PS C:\Users\fbiego\Desktop> py test.py
Traceback (most recent call last):
  File "C:\Users\fbiego\Desktop\test.py", line 31, in <module>
    text = lv.label_get_text(ui_text)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\fbiego\AppData\Local\Programs\Python\Python311\Lib\site-packages\lvgl\__init__.py", line 40687, in label_get_text
    return _get_py_obj(res, 'char')
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\fbiego\AppData\Local\Programs\Python\Python311\Lib\site-packages\lvgl\__init__.py", line 53, in _get_py_obj
    res = cls(c_obj)
          ^^^^^^^^^^
  File "C:\Users\fbiego\AppData\Local\Programs\Python\Python311\Lib\site-packages\lvgl\__init__.py", line 641, in __new__
    instance._obj = value.encode('utf-8')
                    ^^^^^^^^^^^^
AttributeError: cdata 'char *' has no attribute 'encode'
PS C:\Users\fbiego\Desktop>
kdschlosser commented 1 year ago

ok edit the __init__.py file and go to line 633. You should see class _String replace that class with the code below.

class _String(str, _AsArrayMixin):
    _obj = None

    def as_dict(self):
        return self._obj

    def __new__(cls, value):
        try:
            obj = value.encode('utf-8')
            c_obj = _lib_lvgl.ffi.from_buffer(obj)
        except AttributeError:
            c_obj = value
            value = bytes(_lib_lvgl.ffi.buffer(value)).decode('utf-8')

        instance = super().__new__(cls, value)
        instance._obj = c_obj
        return instance
fbiego commented 1 year ago

It now returns the first character only

kdschlosser commented 1 year ago

OYE!!!

at least it is a result. LOL.

I will be making a new branch some time today. The new code doesn't use CFFI at all. Handling of these kinds of things in CFFI is impossible to do because there is know knowledge of how long the returned value is. While it is expected that the last character is going to be '\x00' CFFI doesn't know that so unless I specify a length (which is unknown) there is no way to copy the information over to a python buffer.

One of the many reasons why I stopped using CFFI. The code I am using not is not perfect either but it has less issues than using CFFI and I am able to alter the behavior to make it work. There are still edge case issues but the core of it is functioning as it should. I have gotten the equalizer UI demo from Squareline Studio to work and that is a fairly complex UI. I also got most of the knob demo UI to work which is good.

The biggest problem I am having now is memory leaks do to the lack of attachment between the C code and Python code. No reference counting is done for native C objects and I am only able to weak reference Python objects. So in the example of sending in some text to an LVGL widget the text has to be converted into a bytes object if the function parameter is declared as a "const" and if it is not then I have to convert the text to a byte array and attach the byte array as a buffer to the c type that gets passed. The problem here is holding a reference to that bytearray. If it goes out of scope an access violation will occur so I have to keep a reference to it and when I do that there is no way for me to know if the underlying widget is still in use and if the widget is not that reference cannot be garbage collected.

Those are the issues I am trying to work with now.

kdschlosser commented 1 year ago

OK so I pushed the most recent changes to the develop branch. The CI is running right now for it. I am hopeful that it will complete without any errors. I know the Windows build should complete without an issue.

I still have to update the documentation. it is not going to be 100% correct.. Because of how I had to deal with arrays you will need to do the following in order to convert a char pointer returned from a function into an actual string.

text = lv.label_get_text(ui_text)
text = text * 500  # some number that is going to be larger than the amount of text returned.

by multiplying the returned value by an expected number of items in an array that will do the conversion. In the case of a char array it will run until either a \x00 is encountered or the string reaches the size of the supplied number. Whichever happens first.

There is another way I can handle this I think and I am going to mess about with it a bit to see what happens. If the returned value is actually a char array I should be able to simply return the string. I have to have some coded added to check the data type of the returned value and go from there.