1Gtk2::Ex::FormFactory::UIsnetrroC(o3n)tributed Perl DocuGmtekn2t:a:tEixo:n:FormFactory::Intro(3)
2
3
4
6 Gtk2::Ex::FormFactory::Intro - Introduction into the FormFactory
7 framework
8
10 The Gtk2::Ex::FormFactory framework is for Perl Gtk2 developers who (at
11 least partially ;) agree with these statements:
12
13 • GUI programming is fun but often boring
14
15 • A lot of tasks in GUI programming are similar and misleads the lazy
16 programmer to do too much Copy'n Paste
17
18 • RAD tools like Glade are fine for small applications but not if you
19 want to have a consistent look and feel in bigger and modular
20 applications
21
22 Gtk2::Ex::FormFactory tries to help you with these issues by
23
24 • Strictly separating GUI design, application logic and data
25 structures
26
27 • Giving the developer a more declarative style of defining the
28 structure of your GUI
29
30 • Giving the developer the possibility of definiting the design of the
31 GUI at a single spot in your program
32
33 • Being lightweight and easy to learn.
34
35 Enough buzzwords
36 Imagine you want to build a configuration dialog for your application,
37 which consists of a notebook, to distinguish several topics, each
38 containing a bunch of simpler widgets (in the following example a
39 single text entry). Also it should have the usual Ok and Cancel
40 buttons.
41
42 The straight approach often is to code all the stuff by hand or "draw"
43 all widgets using Glade. At any rate you need to take care of:
44
45 • Consistent look and feel, e.g. labels should be bold and properly
46 aligned to the widgets; the widgets iteslf should have some space
47 around them, buttons should always be aligned to the form above etc.
48
49 • Initializing the widgets with the actual content of your
50 configuration data
51
52 • Either connecting a lot of signals to track the changes the user
53 made. This would apply all changes straight to your internal data
54 structure, which may make implementing the Cancel button difficult
55 or impossible
56
57 • Or grabbing all (changed) data from the widgets, when the user hit
58 the Ok button resp. simply close the window, when the user hit the
59 Cancel button
60
61 That's a lot of stuff, which needs to be repeated for every single
62 dialog in your application. No fun anymore.
63
64 Gtk2::Ex::FormFactory will do the boring stuff for you. That's how it
65 works:
66
67 Register your objects to the Context
68 Create a Gtk2::Ex::FormFactory::Context object and register all your
69 objects, which should be presented/changed by the GUI, here:
70
71 my $context = Gtk2::Ex::FormFactory::Context->new;
72 $context->add_object (
73 name => "config",
74 object => $config_object
75 );
76
77 $config_object has at least the following methods in our example below:
78
79 - get_data_dir()
80 - get_selected_page()
81 - set_data_dir()
82 - set_selected_page()
83
84 The Context is a layer which encapsulates the methods of accessing your
85 object's attributes. Also the Context knows about relationships between
86 objects and/or their attributes, so it's able to handle correspondent
87 updates on the GUI side automatically. We will discuss more details of
88 Gtk2::Ex::FormFactory::Context later in this document.
89
90 Define the structure of your GUI
91 Create Gtk2::Ex::FormFactory object and define the structure of your
92 GUI. E.g, you want to have window which contains a notebook, which
93 consists of a few pages with a bunch of text entries in them. This will
94 look this way: [ very compressed and evil nesting for this document -
95 for bigger dialogs you will break this into several pieces ]
96
97 my $ff = Gtk2::Ex::FormFactory->new (
98 context => $context,
99 content => [
100 Gtk2::Ex::FormFactory::Window->new(
101 title => "Preferences",
102 content => [
103 Gtk2::Ex::FormFactory::Notebook->new (
104 attr => "config.selected_page",
105 content => [
106 Gtk2::Ex::FormFactory::VBox->new (
107 title => "Filesystem",
108 content => [
109 Gtk2::Ex::FormFactory::Form->new (
110 content => [
111 Gtk2::Ex::FormFactory::Entry->new (
112 attr => "config.data_dir",
113 label => "Data Directory",
114 tip => "This directory takes all your files.",
115 rules => "writable-directory",
116 ),
117 ],
118 ),
119 ],
120 ),
121 ],
122 );
123 Gtk2::Ex::FormFactory::DialogButtons->new
124 ],
125 ),
126 ],
127 );
128
129 $ff->open; # actually build the GUI and open the window
130 $ff->update; # fill in the values from $config_object
131
132 So now you defined that you want to have a text entry, which contains a
133 valid writable directory name, which should be inside a form on a
134 notebook page. No details about the exact layout yet, this is just the
135 strucure of your dialog
136
137 But how is this rendered?
138 For this task Gtk2::Ex::FormFactory creates a
139 Gtk2::Ex::FormFactory::Layout object which takes care of all the
140 rendering details. Gtk2::Ex::FormFactory has a default implementation
141 of this, but you can easily inherit from this module to define your own
142 layout (that's mainly for what all this is good for!) and pass it to
143 the FormFactory as the layouter.
144
145 The Layout module mainly consists of two types of methods
146
147 Methods for building a widget
148 build_TYPE() methods for each FormFactory widget type (Entry,
149 SelectList, Popup, Foo etc.) you use in your dialog. These have
150 the Gtk2 code actually necessary to create the corresponding Gtk2
151 widgets.
152
153 Methods for adding a widget to a container
154 These are the so called add_WIDGET_to_CONTAINER() methods, which
155 specify how a particular widget type is added to a particular
156 container type. E.g. they're responsible for consistent looking
157 labels beside widgets etc.
158
159 Because the details of adding a widget mainly depend on the
160 container the widget is added to, there are generic methods for
161 adding arbitrary widgets to a container. If there is no specific
162 method for a widget type this generic method is called instead.
163
164 Layout methods for our example
165 The Layout implementation needs the following methods, to be able to
166 generate a layout for our FormFactory defined above:
167
168 build_window => creates a Gtk2::VBox in a Gtk2::Window
169 build_notebook => creates a Gtk2::Notebook
170 build_form => creates a Gtk2::Table (2 columns)
171 build_entry => creates a Gtk2::Entry
172 build_dialog_buttons => creates a ButtonBox with Ok/Apply/Cancel
173
174 add_widget_to_form => adds entry to table, label in 1st column
175 add_widget_to_notebook => adds form to notebook with tab title
176 add_widget_to_window => adds notebook and buttonbox to the window
177
178 If you regularly code applications with Gtk2 you know, that none of
179 this tasks is rocket science. But you have a lot of parameters for each
180 widget in question to take care of (simply think of the border_width
181 property which may lead to an ugly misaligned mess, if you don't handle
182 it really consistently)
183
184 Because you define this tasks at a single point in your program, it's
185 really easy to create a consistently looking application. Or to change
186 the look quickly. E.g. you decide to put a frame around all your forms?
187 Just change one method - build_form() - and you're done!
188
189 Huh, a lot of new Widget classes to learn!
190 Not really. The FormFactory Widget classes are very simple and mainly
191 wrap correspondent Gtk2 widgets, so you don't need to learn much more.
192
193 Using the builtin widgets is really easy. They all ship with a manual
194 page describing their specific attributes, which usualy isn't much.
195
196 Also Gtk2::Ex::FormFactory has some nifty wrappers for really
197 inconvenient Gtk2 widgets, like Gtk2::Table. Take a look at
198 Gtk2::Ex::FormFactory::Table to learn how easy programming complex
199 table layouts can be. Or look at Gtk2::Ex::FormFactory::Image which is
200 a nice image widget which resizes the image automatically in
201 configurable ranges.
202
203 Building your own FormFactory widgets
204 If you need more widgets: implement them on your own.
205 Gtk2::Ex::FormFactory widget classes don't have much Gtk2 code in them,
206 they just define the properties, which represent this particular form
207 item and implement mainly the following methods:
208
209 • Define a short name for the type (e.g. "entry" for a Gtk2::Entry -
210 the Layout->add_X_to_Y() methods are derived from the short name)
211
212 • Transfer the object's attribute value to the widget
213
214 • Transfer the widget's value to the object's attribute
215
216 • Connect the 'changed' signal for a synchronized dialog, e.g. if you
217 want to react immedately on user input
218
219 What the widget and object "value" actually is (a scalar, hash, array
220 or complex structure) may be arbitrarly defined. How object attributes
221 are accessed, is defined in the Context module. Our example uses the
222 default set_foo(), get_foo() style accessors, but there are more
223 methods up to defining callbacks, which can do very complex lookups.
224
225 Data consistency
226 Now we know that the FormFactory suite solve layout issues very well.
227 Another important feature is automatic data consistency resp. keeping
228 the GUI and your application data in sync.
229
230 Change an object attribute: the correspondent GUI widgets will update
231 automatically. The user entered data to a text entry: the object
232 attribute associated with this entry will automatically get the new
233 text.
234
235 Gtk2::Ex::FormFactory must know your application's objects very well to
236 do such a magic. That's what the Gtk2::Ex::FormFactory::Context module
237 is good for, mentioned shortly at the top of our example.
238
239 Abstraction from your application's objects
240 All your application objects are registered with a unique name to the
241 Context module. Each FormFactory has a reference to this Context, so it
242 know the objects which are registered.
243
244 When you register your object to the Context, you may specify how
245 attributes are accessed by setting prefixes for read/write accessors.
246
247 You may even override methods inside the Context by specifying
248 correspondent closures, which are called instead of the original
249 method.
250
251 Also objects in terms of the Context module may be abstract things like
252 "The currently selected disc from the currently selected artist", not
253 only a simply hardwired object reference. This is done by calling a
254 closure returning the actual object instead of using a hardwired
255 object.
256
257 This way dependend widgets update automaticly, as soon as the
258 correspondent selection changes, e.g. updating a list of CD titles when
259 switching to another disc in an imaginary CD database program.
260
261 Widget consistency
262 Another challenge in a good GUI program is to make your widgets
263 consistent in terms of graying out widgets, which are not useful in a
264 particular state of your program.
265
266 Gtk2::Ex::FormFactory manages visibility and sensivity of your widgets
267 automatically for you once you registered the correspondent
268 dependencies at the Context. E.g. if there currently is no CD album
269 selected, the corresponding fields are greyed out automatically,
270 including the field labels.
271
272 Data validity
273 Gtk2::Ex::FormFactory specifies Gtk2::Ex::FormFactory::Rules, which are
274 checked against the values the user entered. These conditions must
275 apply, otherwise the old values are restored automatically. A bunch of
276 rules are shipped, but you can define your own set by specifying a
277 correspondent rule object or closures.
278
279 Extensibility
280 This framework was designed with extensibility in mind. You can
281
282 • Define your own FormFactory widgets, by simply using the base class
283 Gtk2::Ex::FormFactory::Widget resp.
284 Gtk2::Ex::FormFactory::Container. No matter how complex your widget
285 is as long as you provide correspondent object attribute accessors,
286 which transfer the widget's state to the object and vice versa.
287
288 • Define your own FormFactory Layout module, by deriving from the
289 default Layout implementation and passing a correspondent object to
290 the FormFactory constructor.
291
292 • All items in your FormFactory have a name, which will be set by
293 default or to a value, you pass to the item's constructor. This way
294 your Layout implementation can even do very special things for very
295 special widgets, without the need of creating an extra Widget module
296 for this.
297
298 • You can request any Gtk widget from a FormFactory widget by name to
299 do further manipulation, although you should consider doing this
300 inside your Layout implementation, to keep the "single point of
301 layout" rule.
302
304 Jörn Reder <joern at zyn dot de>
305
307 Copyright 2004-2006 by Jörn Reder.
308
309 This library is free software; you can redistribute it and/or modify it
310 under the terms of the GNU Library General Public License as published
311 by the Free Software Foundation; either version 2.1 of the License, or
312 (at your option) any later version.
313
314 This library is distributed in the hope that it will be useful, but
315 WITHOUT ANY WARRANTY; without even the implied warranty of
316 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
317 Library General Public License for more details.
318
319 You should have received a copy of the GNU Library General Public
320 License along with this library; if not, write to the Free Software
321 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307
322 USA.
323
325 Hey! The above document had some coding errors, which are explained
326 below:
327
328 Around line 399:
329 Non-ASCII character seen before =encoding in 'Jörn'. Assuming UTF-8
330
331
332
333perl v5.34.0 2022-01-21 Gtk2::Ex::FormFactory::Intro(3)