Widgets are components¶
Widgets are what we call “components”, which are a central part of the event system. They are what allows widgets to have properties and react to things happening in other parts of the application. But let’s not get ahead of ourselves; the event system is dicsussed in the next chapter.
For the moment, it’s enough to know that the
class is kind of
thing is that you can still use these objects in Python, by setting their properties,
invoking their actions, and reacting to their state. This is possible because
of so-called proxy objects.
We mentioned earlier that the
PyWidget can be used to
create widgets that live in Python: these are a kind of
their actions and methods are executed in Python. And yes, they can be used
from JS by setting properties, invoking action and reacting to state.
PyComponent and JsComponent¶
- They are both associated with a
- They have an
idattribute that is unique within their session, and a
uidattribute that is globally unique.
PyComponentcan only be instantiated in Python, a
JsComponentmay have a proxy object in Python; these proxy objects are created automatically when Python references the component.
In practice, you’ll use
PyComponents to implement Python-side behavior,
allows a variety of ways by which you can tie Python and JS together, but
this can be a pitfall. It’s important to think well about what parts of your
are discussed later in the guide.
(And the plain
Component class? It can be
used (both in Python and JS), but is unaware of anything “on the other side”.
It’s use in Flexx is therefore limited.)
The proxy components allow the “other side” to inspect properties, invoke actions and connect to events. The real component is aware of what events the proxy reacts to, and will only communicate these events.
The example below may be a bit much to digest. Don’t worry about that. In most cases things should just work.
from flexx import flx class Person(flx.JsComponent): # Lives in Js name = flx.StringProp(settable=True) age = flx.IntProp(settable=True) @flx.action def increase_age(self): self._mutate_age(self.age + 1) class PersonDatabase(flx.PyComponent): # Lives in Python persons = flx.ListProp() @flx.action def add_person(self, name, age): with self: # new components need a session p = Person(name=name, age=age) self._mutate_persons([p], 'insert', 99999) @flx.action def new_year(self): for p in self.persons: p.increase_age()
In the above code, the
database object that keeps a list of them lives in Python. In practice,
Person components will e.g. have a visual representation in the
browser. The database could also have been a
JsComponent, but let’s
assume that we need it in Python because it synchronizes to a mysql
database or something.
We can observe that the
add_person action (which executes in Python)
Person objects. Actually, it instantiates proxy objects that
automatically get corresponding (real)
new_year action executes in Python, which in turn invokes the
Actions and events cross the boundary¶
It’s important to realize that actions of a component can be invoked from anywhere.
In the above example,
Person.set_name("Guido") can be called from
Python (e.g. by the
The root component and active components¶
Another useful feature is that each component has a
root attribute that
holds a reference to the component representing the root of the application.
E.g. if the root is a
JsComponent objects have a
reference to (a proxy of) this database.
Further, when a component is used as a context manager, it becomes an
“active component”. We’ve already seen how this is used to structure
child widgets. Sometimes you may want to know which components are active,
which you can do with