| 1 | # $Id: composite.pod 1.2 Wed, 12 Nov 1997 00:30:45 +0100 ach $ |
| 2 | |
| 3 | =head1 NAME |
| 4 | |
| 5 | Tk::composite - Defining a new composite widget class |
| 6 | |
| 7 | =for category Derived Widgets |
| 8 | |
| 9 | =head1 SYNOPSIS |
| 10 | |
| 11 | package Tk::Whatever; |
| 12 | |
| 13 | require Tk::Derived; |
| 14 | require Tk::Frame; # or Tk::Toplevel |
| 15 | @ISA = qw(Tk::Derived Tk::Frame)'; # or Tk::Toplevel |
| 16 | |
| 17 | Construct Tk::Widget 'Whatever'; |
| 18 | |
| 19 | sub ClassInit |
| 20 | { |
| 21 | my ($class,$mw) = @_; |
| 22 | |
| 23 | #... e.g., class bindings here ... |
| 24 | $class->SUPER::ClassInit($mw); |
| 25 | } |
| 26 | |
| 27 | sub Populate |
| 28 | { |
| 29 | my ($cw,$args) = @_; |
| 30 | |
| 31 | my $flag = delete $args->{-flag}; |
| 32 | if (defined $flag) |
| 33 | { |
| 34 | # handle -flag => xxx which can only be done at create |
| 35 | # time the delete above ensures that new() does not try |
| 36 | # and do $cw->configure(-flag => xxx); |
| 37 | } |
| 38 | |
| 39 | $cw->SUPER::Populate($args); |
| 40 | |
| 41 | $w = $cw->Component(...); |
| 42 | |
| 43 | $cw->Delegates(...); |
| 44 | |
| 45 | $cw->ConfigSpecs( |
| 46 | '-cursor' => [SELF,'cursor','Cursor',undef], |
| 47 | '-something' => [METHOD,dbName,dbClass,'default'], |
| 48 | '-text' => [$label,dbName,dbClass,'default'], |
| 49 | '-heading' => [{-text=>$head}, |
| 50 | heading,Heading,'My Heading'], |
| 51 | ); |
| 52 | } |
| 53 | |
| 54 | sub something |
| 55 | { |
| 56 | my ($cw,$value) = @_; |
| 57 | if (@_ > 1) |
| 58 | { |
| 59 | # set it |
| 60 | } |
| 61 | return # current value |
| 62 | } |
| 63 | |
| 64 | 1; |
| 65 | |
| 66 | __END__ |
| 67 | |
| 68 | # Anything not documented is *private* - your POD is god, so to speak. |
| 69 | |
| 70 | =head1 NAME |
| 71 | |
| 72 | Tk::Whatever - a whatever widget |
| 73 | |
| 74 | =head1 SYNOPSIS |
| 75 | |
| 76 | use Tk::Whatever; |
| 77 | |
| 78 | $widget = $parent->Whatever(...); |
| 79 | |
| 80 | =head1 DESCRIPTION |
| 81 | |
| 82 | You forgot to document your widget, didn't you? :-) |
| 83 | |
| 84 | ... |
| 85 | |
| 86 | =head1 DESCRIPTION |
| 87 | |
| 88 | The intention behind a composite is to create a higher-level widget, |
| 89 | sometimes called a "super-widget" or "meta-widget". Most often, |
| 90 | a composite will be |
| 91 | built upon other widgets by B<using> them, as opposed to specializing on them. |
| 92 | For example, the supplied composite widget B<LabEntry> is I<made of> an |
| 93 | B<Entry> and a B<Label>; it is neither a I<kind-of> B<Label> |
| 94 | nor is it a I<kind-of> B<Entry>. |
| 95 | |
| 96 | Most of the work of a composite widget consist in creating subwidgets, |
| 97 | arrange to dispatch configure options to the proper subwidgets and manage |
| 98 | composite-specific configure options. |
| 99 | |
| 100 | =head1 GLORY DETAILS |
| 101 | |
| 102 | Depending on your perl/Tk knowledget this section may be enlighting |
| 103 | or confusing. |
| 104 | |
| 105 | =head2 Composite Widget |
| 106 | |
| 107 | Since perl/Tk is heavilly using an object-oriented approach, it is no |
| 108 | suprise that creating a composite goes through a B<new()> method. |
| 109 | However, the composite does not normally define a B<new()> method |
| 110 | itself: it is usually sufficient to simply inherit it from |
| 111 | B<Tk::Widget>. |
| 112 | |
| 113 | This is what happens when the composite use |
| 114 | |
| 115 | @ISA = qw(Tk::Frame); # or Tk::Toplevel |
| 116 | |
| 117 | to specify its inheritance chain. To complete the initialisation of the |
| 118 | widget, it must call the B<Construct> method from class B<Widget>. That |
| 119 | method accepts the name of the new class to create, i.e. the package name |
| 120 | of your composite widget: |
| 121 | |
| 122 | Construct Tk::Widget 'Whatever'; |
| 123 | |
| 124 | Here, B<Whatever> is the package name (aka the widget's B<class>). This |
| 125 | will define a constructor method for B<Whatever>, normally named after the |
| 126 | widget's class. Instanciating that composite in client code would |
| 127 | the look like: |
| 128 | |
| 129 | $mw = MainWindow->new(); # Creates a top-level main window |
| 130 | |
| 131 | $cw = $mw->Whatever(); # Creates an instance of the |
| 132 | # composite widget Whatever |
| 133 | |
| 134 | Whenever a composite is instanciated in client code, |
| 135 | C<Tk::Widget::new()> will be invoked via the widget's class |
| 136 | constructor. That B<new> method will call |
| 137 | |
| 138 | $cw->InitObject(\%args); |
| 139 | |
| 140 | where I<%args> is the arguments passed to the widget's constructor. Note |
| 141 | that B<InitObject> receives a B<reference> to the hash array |
| 142 | containing all arguments. |
| 143 | |
| 144 | For composite widgets that needs an underlying frame, B<InitObject> |
| 145 | will typically be inherited from B<Tk::Frame>, that is, no method of |
| 146 | this name will appear in the composite package. For composites that |
| 147 | don't need a frame, B<InitObject> will typically be defined in the |
| 148 | composite class (package). Compare the B<LabEntry> composite with |
| 149 | B<Optionmenu>: the former is B<Frame> based while the latter is B<Widget> |
| 150 | based. |
| 151 | |
| 152 | In B<Frame> based composites, B<Tk::Frame::InitObject()> will call |
| 153 | B<Populate()>, which should be defined to create the characteristic |
| 154 | subwidgets of the class. |
| 155 | |
| 156 | B<Widget> based composites don't need an extra B<Populate> layer; they |
| 157 | typically have their own B<InitObject> method that will create subwidgets. |
| 158 | |
| 159 | =head2 Creating Subwidgets |
| 160 | |
| 161 | Subwidget creation happens usually in B<Populate()> (B<Frame> based) |
| 162 | or B<InitObject()> (B<Widget> based). The composite usually calls the |
| 163 | subwidget's constructor method either directly, for "private" subwidgets, |
| 164 | or indirectly through the B<Component> method for subwidgets that should |
| 165 | be advertised to clients. |
| 166 | |
| 167 | B<Populate> may call B<Delegates> to direct calls to methods |
| 168 | of chosen subwidgets. For simple composites, typically most if not all |
| 169 | methods are directed |
| 170 | to a single subwidget - e.g. B<ScrListbox> directs all methods to the core |
| 171 | B<Listbox> so that I<$composite>-E<gt>B<get>(...) calls |
| 172 | I<$listbox>-E<gt>B<get>(...). |
| 173 | |
| 174 | =head2 Further steps for Frame based composites |
| 175 | |
| 176 | B<Populate> should also call B<ConfigSpecs()> to specify the |
| 177 | way that configure-like options should be handled in the composite. |
| 178 | Once B<Populate> returns, method B<Tk::Frame::ConfigDefault> |
| 179 | walks through the B<ConfigSpecs> entries and populates |
| 180 | %$args hash with defaults for options from X resources (F<.Xdefaults>, etc). |
| 181 | |
| 182 | When B<InitObject()> returns to B<Tk::Widget::new()>, |
| 183 | a call to B<$cw>-E<gt>I<configure>(%$args) is made which sets *all* |
| 184 | the options. |
| 185 | |
| 186 | =head1 SEE ALSO |
| 187 | |
| 188 | L<Tk::ConfigSpecs|Tk::ConfigSpecs> |
| 189 | L<Tk::Derived|Tk::Derived> |
| 190 | |
| 191 | =cut |
| 192 | |