August'24: Kamaelia is in maintenance mode and will recieve periodic updates, about twice a year, primarily targeted around Python 3 and ecosystem compatibility. PRs are always welcome. Latest Release: 1.14.32 (2024/3/24)
A Graphline provides a flexible way to link inboxes and outboxes in any way you wish. Whereas a Pipeline constrains your components to be wired into ... a pipeline ... with Graphline you specify each link explicitly.
Suppose we want to build a simple slideshow application, where pygame Button components control a Chooser component that sends filenames for each slide to a pygame Image display component:
We could build this by writing a new component with a whole bunch of
self.link() calls to link each outbox to the next inbox. But that is a
lot of code to write and rather tedious! ... surely there must be an
easier way?
... You need the graphline component! No need to write a whole new
component, simply use a Graphline component like this:
from Kamaelia.Chassis.Graphline import Graphline
from Kamaelia.UI.Pygame.Button import Button
from Kamaelia.UI.Pygame.Image import Image
from Kamaelia.Util.Chooser import Chooser
files = [ "slide1.gif", "slide2.gif", .... "slide99.gif" ]
Graphline(
CHOOSER = Chooser(files),
IMAGE = Image(size=(800,600), position=(8,48)),
NEXT = Button(caption="Next", msg="NEXT", position=(72,8) ),
PREVIOUS = Button(caption="Previous", msg="PREV" ,position=(8,8) ),
FIRST = Button(caption="First", msg="FIRST",position=(256,8) ),
LAST = Button(caption="Last", msg="LAST" ,position=(320,8) ),
linkages = {
("NEXT", "outbox") : ("CHOOSER", "inbox"),
("PREVIOUS", "outbox") : ("CHOOSER", "inbox"),
("FIRST", "outbox") : ("CHOOSER", "inbox"),
("LAST", "outbox") : ("CHOOSER", "inbox"),
("CHOOSER", "outbox") : ("IMAGE", "inbox"),
}
).run()
What you see here is slightly abridged for clarity. You can find the
full version in
Kamaelia/Examples/SimpleGraphicalApps/Slideshows
What did we just do? Simple:
Write each component as a named argument
CHOOSER = Chooser(files),
IMAGE = Image(size=(800,600), position=(8,48)),
NEXT = Button(caption="Next", msg="NEXT", position=(72,8) ),
PREVIOUS = Button(caption="Previous", msg="PREV" ,position=(8,8) ),
FIRST = Button(caption="First", msg="FIRST",position=(256,8) ),
LAST = Button(caption="Last", msg="LAST" ,position=(320,8) ),
...then write the linkages you want as the 'linkages' argument in
a dictionary:
linkages = {
("NEXT", "outbox") : ("CHOOSER", "inbox"),
("PREVIOUS", "outbox") : ("CHOOSER", "inbox"),
("FIRST", "outbox") : ("CHOOSER", "inbox"),
("LAST", "outbox") : ("CHOOSER", "inbox"),
("CHOOSER", "outbox") : ("IMAGE", "inbox"),
}
For each linkage we want, we write a mapping in the dictionary from a (component, outbox) to a (component, inbox) We refer to the components by the names we just gave them, as strings. We reference the inboxes and outboxes by their names too.
So, for example:
("NEXT","outbox") : ("CHOOSER","inbox")
specifies that you want the "outbox" outbox of the "Next" Button to
be linked to the "inbox" inbox of the Chooser.
So the Graphline defined above wires up the Chooser, Image and 4
Button components inside itself - like Pipeline it is a kind of
container:
If we look in more detail, the links made are actually like this:
Just like the Pipeline component, a Graphline has its own inboxes and
outboxes. You can specify links to and from these by using the empty
string to name the component.
For example, we might want to be able to send instructions to the
Chooser from outside this graphline, in which case we would add this to
the set of linkages:
("", "inbox") : ("NEXT", "inbox"),
By using a name for a component that we've not used (in this case
simply the empty string suffices) we're telling Graphline to use its own
inbox.
We could do the same for outboxes too if we want. For example, we could
ask for the outbox of the Image component to be linked to the
Graphline's outbox:
("IMAGE", "outbox") : ("", "outbox"),
In fact, if you also refer to an inbox or outbox name for the
Graphline that does not exist. Graphline will simply create it. This
means you can use a Graphline as a container, giving it whatever inboxes
and outboxes you need - not just the 'standard' ones that most
components have.
Just like with Pipeline, Graphline is a fully fledged component itself,
so you can put a Graphline inside a Pipeline, or a Pipeline inside a
Graphline, or any other combination you care to choose. Again, it can be
a good way of making your system more modular, by separating off a
little group of components into a separate functional unit.