source: orange/docs/extend-widgets/rst/api.rst @ 11424:ccb4a5fac5e1

Revision 11424:ccb4a5fac5e1, 4.8 KB checked in by Ales Erjavec <ales.erjavec@…>, 13 months ago (diff)

More fixes to Widgets Development documentation

RevLine 
[11049]1#############################################
2Orange Widgets Reference Guide for Developers
3#############################################
4
5***********************************
6Channels Definitions, Data Exchange
7***********************************
8
9Input and output channels are defined anywhere within the
10:obj:`__init__` function of a main widget class. The definition
11is used when running a widget, but also when registering your widget
12within Orange Canvas. Channel definitions are optional, depending on
13what your widget does.
14
15Output Channels
16***************
17
18Following is an example that defines two output channels::
19
[11424]20    self.outputs = [("Sampled Data", orange.ExampleTable),
21                    ("Learner", orange.Learner)]
[11049]22
23:obj:`self.outputs` should thus be a list of tuples, within
24each the first element is a name of the channel, and the second the
25type of the tokens that will be passed through. Token types are class
26names; most often these are some Orange classes, but they can also be
27anything you may define as class in Python.
28
29Widgets send the data by using :obj:`self.send` call,
30like::
31
32    self.send("Sampled Data", mydata)
33
34Parameters of :obj:`send` are channel name and a token to be
35send (e.g., a variable that holds the data to be send through the
36channel).
37
38When tokens are send around, the signaling mechanism annotates
39them with a pointer to an object that sent the toke (e.g., a widget
40id). Additionally, this annotation can be coupled with some name
41passed to :obj:`send`, in case you have a widget that can send
42few tokens one after the other and you would like to enable a receiving widget
43recognize these are different tokens (and not updates of the same
44one)::
45
46    id = 10
47    self.send("Sampled Data", mydata, id)
48
49**************
50Input Channels
51**************
52
53An example of the simplest definition of an input channel is::
54
55    self.inputs = [("Data", orange.ExampleTable, self.receiveData)]
56
57Again, :obj:`self.inputs` is a list of tuples, where the
58elements are the name of the channel, followed by a channel type and a
59Python function that will be called with any token received. For the
60channel defined above, a corresponding receiving function would be of
61the type (we would most often define it within the widget class
62defintion, hence :obj:`self` for the first attribute)::
63
64    def receiveData(self, data):
[11424]65        # handle data in some way
66
[11049]67
68Any time our widget would receive a token, :obj:`receiveData`
69would be called. Notice there would be no way of knowing anything
70about the sender of the token, hence widget would most often replace
71the previously received token with the new one, and forget about the
72old one.
73
74Widgets can often clear their output by sending a :obj:`None`
75as a token. Also, upon deletion of some widget, this is the way that
76Orange Canvas would inform all directly connected downstream widgets
77about deletion. Similar, when channels connecting two widgets are
78deleted, Orange Canvas would automatically send :obj:`None` to
79the receiving widget. Make sure your widget handles :obj:`None`
[11424]80tokens appropriately!
[11049]81
82There are cases when widget would like to know about the origin of
83a token. Say, you would like to input several learners to the
84evaluation widget, how would this distinguish between the learners of
85different origins? Remember (from above) that tokens are actually
86passed around with IDs (pointers to widgets that sent them). To
87declare a widget is interested about these IDs, one needs to define an
88input channel in the following way::
89
90    self.inputs = [("Learners", orange.Learner, self.learner, Multiple)]
91
92where the last argument refers if we have a "Single" (default if not
93specified) or a "Multiple" channel. For the above declared channel, the
94receiving function should include an extra argument for the ID, like::
95
96   def learner(self, learnertoken, tokenid):
[11424]97       # handle learnertoken and tokeid in some way
[11049]98
99Widgets such as :obj:`OWTestLearners` and alike use such
100schema.
101
102Finally, we may have input channels of the same type. If a widget
103would declare input channels like::
104
105    self.inputs = [("Data", orange.ExampleTable, self.maindata),
[11424]106                   ("Additional Data", orange.ExampleTable, self.otherdata)]
[11049]107
108and we connect this widget in Orange Canvas to a sending widget
109that has a single orange.ExampleTable output channel, Canvas would
[11424]110bring up *Set Channels* dialog. There, a sending widget's channel could
[11049]111be connected to both receiving channels. As we would often prefer to
112connect to a single (default) channel instead (still allowing user of
113Orange Canvas to set up a different schema manually), we set that channel
114as the default. We do this by the using the fourth element in the channel
115definition list, like::
116
117    self.inputs = [("Data", orange.ExampleTable, self.maindata, Default),
[11424]118                   ("Additional Data", orange.ExampleTable, self.otherdata)]
Note: See TracBrowser for help on using the repository browser.