Pārlūkot izejas kodu

switch to new binding library

Falko Schindler 4 gadi atpakaļ
vecāks
revīzija
3915a3d2ce

+ 8 - 12
main.py

@@ -47,25 +47,21 @@ with ui.row():
         ui.label('Binding', 'h5')
         ui.label('Binding', 'h5')
         with ui.row():
         with ui.row():
             n1 = ui.number(value=1.2345, format='%.2f')
             n1 = ui.number(value=1.2345, format='%.2f')
-            n2 = ui.number(format='%.3f').bind('value', n1, 'value')
+            n2 = ui.number(format='%.3f').bind_value(n1.value)
         with ui.row():
         with ui.row():
             c = ui.checkbox('c1')
             c = ui.checkbox('c1')
-            s = ui.switch('c2').bind('value', c, 'value')
+            ui.switch('c2').bind_value(c.value)
         with ui.row():
         with ui.row():
             model = type('Model', (), {'value': 1})  # one-liner to define an object with an attribute "value"
             model = type('Model', (), {'value': 1})  # one-liner to define an object with an attribute "value"
-            ui.radio({1: 'a', 2: 'b', 3: 'c'}).bind('value', model, 'value')
-            ui.radio({1: 'A', 2: 'B', 3: 'C'}).bind('value', model, 'value')
+            ui.radio({1: 'a', 2: 'b', 3: 'c'}).bind_value(model.value)
+            ui.radio({1: 'A', 2: 'B', 3: 'C'}).bind_value(model.value)
             with ui.column():
             with ui.column():
-                ui.number().bind('value', model, 'value')
-                ui.slider(min=1, max=3).bind('value', model, 'value')
-                ui.label().bind('text', model, 'value')
+                ui.number().bind_value(model.value)
+                ui.slider(min=1, max=3).bind_value(model.value)
+                ui.label().bind_text(model.value)
         with ui.row().add_classes('items-center'):
         with ui.row().add_classes('items-center'):
             on = ui.icon('visibility')
             on = ui.icon('visibility')
-            ui.checkbox('visible').bind('value', on, 'visible')
-        with ui.row():
-            dict_ = {'key': 'binding to a dictionary'}
-            ui.input().bind('value', dict_, 'key')
-            ui.label().bind('text', dict_, 'key').add_style('margin-top: 2em')
+            ui.checkbox('visible', value=True).bind_value_to(on.visible)
 
 
     with ui.card():
     with ui.card():
         ui.label('Matplotlib', 'h5')
         ui.label('Matplotlib', 'h5')

+ 0 - 52
nicegui/binding.py

@@ -1,52 +0,0 @@
-from typing import Any
-import asyncio
-
-class Binding:
-
-    all_bindings = []
-
-    def __init__(self, element, element_attribute: str, model: Any, model_attribute: str) -> None:
-
-        self.element = element
-        self.element_attribute = element_attribute
-        self.model = model
-        self.model_attribute = model_attribute
-
-    def get_model_value(self):
-
-        if isinstance(self.model, dict):
-            return self.model[self.model_attribute]
-        else:
-            return getattr(self.model, self.model_attribute)
-
-    def set_model_value(self, value):
-
-        if isinstance(self.model, dict):
-            self.model[self.model_attribute] = value
-        else:
-            setattr(self.model, self.model_attribute, value)
-
-    async def update_element(self):
-
-        model_value = self.get_model_value()
-        element_value = getattr(self.element, self.element_attribute)
-        if element_value != model_value:
-            setattr(self.element, self.element_attribute, model_value)
-            await self.element.parent_view.update()
-
-    def update_model(self):
-
-        model_value = self.get_model_value()
-        element_value = getattr(self.element, self.element_attribute)
-        if model_value != element_value:
-            self.set_model_value(element_value)
-
-    @staticmethod
-    async def loop():
-
-        while True:
-
-            for binding in Binding.all_bindings:
-                await binding.update_element()
-
-            await asyncio.sleep(0.1)

+ 3 - 11
nicegui/elements/element.py

@@ -1,11 +1,12 @@
 import justpy as jp
 import justpy as jp
-from ..binding import Binding
+from binding.binding import BindableProperty
 
 
 class Element:
 class Element:
 
 
     wp: None
     wp: None
     view_stack = []
     view_stack = []
-    all_bindings = []
+
+    visible = BindableProperty
 
 
     def __init__(self, view: jp.HTMLBaseComponent, design: str):
     def __init__(self, view: jp.HTMLBaseComponent, design: str):
 
 
@@ -22,8 +23,6 @@ class Element:
 
 
         self.visible = True
         self.visible = True
 
 
-        self.bindings = []
-
     @property
     @property
     def visible(self):
     def visible(self):
 
 
@@ -54,10 +53,3 @@ class Element:
 
 
         self.view.style += ' ' + style
         self.view.style += ' ' + style
         return self
         return self
-
-    def bind(self, attribute, model, model_attribute):
-
-        binding = Binding(self, attribute, model, model_attribute)
-        self.bindings.append(binding)
-        Binding.all_bindings.append(binding)
-        return self

+ 15 - 0
nicegui/elements/label.py

@@ -29,3 +29,18 @@ class Label(Element):
     def set_text(self, text: str):
     def set_text(self, text: str):
 
 
         self.text = text
         self.text = text
+
+    def bind_text_to(self, target):
+
+        self.text.bind_to(target, nesting=1)
+        return self
+
+    def bind_text_from(self, target):
+
+        self.text.bind_from(target, nesting=1)
+        return self
+
+    def bind_text(self, target):
+
+        self.text.bind(target, nesting=1)
+        return self

+ 18 - 14
nicegui/elements/value_element.py

@@ -1,11 +1,14 @@
 import justpy as jp
 import justpy as jp
 from typing import Any, Callable
 from typing import Any, Callable
 import traceback
 import traceback
+from binding import BindableProperty
 from .element import Element
 from .element import Element
 from ..utils import EventArguments
 from ..utils import EventArguments
 
 
 class ValueElement(Element):
 class ValueElement(Element):
 
 
+    value = BindableProperty()
+
     def __init__(self,
     def __init__(self,
                  view: jp.HTMLBaseComponent,
                  view: jp.HTMLBaseComponent,
                  design: str,
                  design: str,
@@ -16,17 +19,7 @@ class ValueElement(Element):
 
 
         self.on_change = on_change
         self.on_change = on_change
         self.value = value
         self.value = value
-
-    @property
-    def value(self):
-
-        return self.value_
-
-    @value.setter
-    def value(self, value: any):
-
-        self.value_ = value
-        self.set_view_value(value)
+        self.value.bind_to(self.view.value)
 
 
     def handle_change(self, msg):
     def handle_change(self, msg):
 
 
@@ -41,6 +34,17 @@ class ValueElement(Element):
             except Exception:
             except Exception:
                 traceback.print_exc()
                 traceback.print_exc()
 
 
-        for binding in self.bindings:
-            if binding.element_attribute == 'value':
-                binding.update_model()
+    def bind_value_to(self, target):
+
+        self.value.bind_to(target, nesting=1)
+        return self
+
+    def bind_value_from(self, target):
+
+        self.value.bind_from(target, nesting=1)
+        return self
+
+    def bind_value(self, target):
+
+        self.value.bind(target, nesting=1)
+        return self

+ 8 - 2
nicegui/nicegui.py

@@ -5,10 +5,11 @@ import sys
 import inspect
 import inspect
 import webbrowser
 import webbrowser
 from pygments.formatters import HtmlFormatter
 from pygments.formatters import HtmlFormatter
+import binding
+import asyncio
 from .ui import Ui
 from .ui import Ui
 from .timer import Timer
 from .timer import Timer
 from .elements.element import Element
 from .elements.element import Element
-from .binding import Binding
 
 
 # start uvicorn with auto-reload; afterwards the auto-reloaded process should not start uvicorn again
 # start uvicorn with auto-reload; afterwards the auto-reloaded process should not start uvicorn again
 if not inspect.stack()[-2].filename.endswith('spawn.py'):
 if not inspect.stack()[-2].filename.endswith('spawn.py'):
@@ -26,10 +27,15 @@ main = jp.Div(a=wp, classes='q-ma-md column items-start', style='row-gap: 1em')
 main.add_page(wp)
 main.add_page(wp)
 jp.justpy(lambda: wp, start_server=False)
 jp.justpy(lambda: wp, start_server=False)
 
 
+async def binding_loop():
+    while True:
+        binding.update()
+        await asyncio.sleep(0.1)
+
 @jp.app.on_event('startup')
 @jp.app.on_event('startup')
 def startup():
 def startup():
     [jp.run_task(t) for t in Timer.tasks]
     [jp.run_task(t) for t in Timer.tasks]
-    jp.run_task(Binding.loop())
+    jp.run_task(binding_loop())
 
 
 Element.wp = wp
 Element.wp = wp
 Element.view_stack = [main]
 Element.view_stack = [main]