1pod::Prima::tutorial(3)User Contributed Perl Documentatiopnod::Prima::tutorial(3)
2
3
4
6 Prima::tutorial - introductory tutorial
7
9 Programming graphic interfaces is often considered a somewhat boring
10 business, and not without a cause. It is a small pride in knowing that
11 your buttons and scrollbars work exactly as millions of others buttons
12 and scrollbars do, so whichever GUI toolkit is chosen, it is usually
13 regarded as a tool of small importance, and the less obtrusive, the
14 better. Given that, and trying to live up to the famous Perl 'making
15 easy things easy and hard things possible' mantra, this manual page is
16 an introductory tutorial meant to show how to write easy things easy.
17 The hard things are explained in the other Prima manual pages ( see
18 Prima ).
19
21 Prima is written and is expected to be used in some traditions of Perl
22 coding, such as DWIM ( do what I mean ) or TMTOWTDI ( there are more
23 than one way to do it). Perl itself is language (arguably) most
24 effective in small programs, as the programmer doesn't need to include
25 lines and lines of prerequisite code before even getting to the problem
26 itself. Prima can't compete with that, but the introductory fee is low;
27 a minimal working 'Hello world' can be written in three lines of code:
28
29 use Prima qw(Application);
30 Prima::MainWindow-> new( text => 'Hello world!');
31 run Prima;
32
33 Line 1 here is the invocation of modules Prima and Prima::Application.
34 Sure, one can explicitly invoke both "use Prima" and "use
35 Prima::Application" etc etc, but as module Prima doesn't export method
36 names, the exemplified syntax is well-suited for such a compression.
37
38 Line 2 creates a window of Prima::MainWindow class, which is visualized
39 as a screen window, titled as 'Hello world'. The class terminates the
40 application when the window is closed; this is the only difference from
41 'Window' windows, that do nothing after their closing. From here,
42 "Prima::" prefix in class names will be omitted, and will be used only
43 when necessary, such as in code examples.
44
45 Line 3 enters the Prima event loop. The loop is terminated when the
46 only instance of Application class, created by "use Prima::Application"
47 invocation and stored in $::application scalar, is destroyed.
48
49 Strictly speaking, a minimal 'hello world' program can be written even
50 in two lines:
51
52 use Prima;
53 Prima::message('Hello world');
54
55 but it is not illustrative and not useful. "Prima::message" is rarely
56 used, and is one of few methods contained in "Prima::" namespace. To
57 display a message, the MsgBox module is often preferred, with its
58 control over message buttons and pre-defined icons. With its use, the
59 code above can be rewritten as
60
61 use Prima qw(Application MsgBox);
62 message('Hello world');
63
64 but where "Prima::message" accepts the only text scalar parameters,
65 "Prima::MsgBox::message" can do lot more. For example
66
67 use Prima qw(Application MsgBox);
68 message('Hello world', mb::OkCancel|mb::Information);
69
70 displays two buttons and an icon. A small achievement, but the
71 following is a bit more interesting:
72
73 use Prima qw(Application MsgBox);
74 message('Hello world', mb::OkCancel|mb::Information,
75 buttons => {
76 mb::Cancel => {
77 # there are predefined color constants to use
78 backColor => cl::LightGreen,
79 # but RGB integers are also o.k.
80 color => 0xFFFFFF,
81 },
82 mb::Ok => {
83 text => 'Indeed',
84 },
85 }
86 );
87
88 The definition of many object properties at once is a major feature of
89 Prima, and is seen throughout the toolkit. Returning back to the very
90 first example, we can demonstrate the manipulation of the window
91 properties in the same fashion:
92
93 use Prima qw(Application);
94 my $window = Prima::MainWindow-> new(
95 text => 'Hello world!',
96 backColor => cl::Yellow,
97 size => [ 200, 200],
98 );
99 run Prima;
100
101 Note that the "size" property is a two-integer array, and color
102 constant is registered in "cl::" namespace. In Prima there is a number
103 of such two- and three-letter namespaces, containing usually integer
104 constants for various purposes. The design reason for choosing such
105 syntax over string constants ( as in Perl-Tk, such as "color =>
106 'yellow'" ) is that the syntax is checked on the compilation stage,
107 thus narrowing the possibility of a bug.
108
109 There are over a hundred properties, such as color, text, or size,
110 defined on descendants of Widget class. These can be set in "new" (
111 alias "create" ) call, or referred later, either individually
112
113 $window-> size( 300, 150);
114
115 or in a group
116
117 $window-> set(
118 text => 'Hello again',
119 color => cl::Black,
120 );
121
122 In addition to these, there are also more than 30 events, called
123 whenever a certain action is performed; the events have syntax
124 identical to the properties. Changing the code again, we can catch a
125 mouse click on the window:
126
127 use Prima qw(Application MsgBox);
128 my $window = Prima::MainWindow-> new(
129 text => 'Hello world!',
130 size => [ 200, 200],
131 onMouseDown => sub {
132 my ( $self, $button, $mod, $x, $y) = @_;
133 message("Aww! You've clicked me right in $x:$y!");
134 },
135 );
136 run Prima;
137
138 While an interesting concept, it is not really practical if the only
139 thing you want is to catch a click, and this is the part where a
140 standard button probably should be preferred:
141
142 use Prima qw(Application Buttons MsgBox);
143 my $window = Prima::MainWindow-> new(
144 text => 'Hello world!',
145 size => [ 200, 200],
146 );
147 $window-> insert( Button =>
148 text => 'Click me',
149 growMode => gm::Center,
150 onClick => sub { message("Hello!") }
151 );
152 run Prima;
153
154 For those who know Perl-Tk and prefer its ways to position a widget,
155 Prima provides pack and place interfaces. Here one can replace the line
156
157 growMode => gm::Center,
158
159 to
160
161 pack => { expand => 1 },
162
163 with exactly the same effect.
164
166 Prima contains a set of standard ( in GUI terms ) widgets, such as
167 buttons, input lines, list boxes, scroll bars, etc etc. These are
168 diluted with the other more exotic widgets, such as POD viewer or
169 docking windows. Technically, these are collected in "Prima/*.pm"
170 modules and each contains its own manual page, but for informational
171 reasons here is the table of these, an excerpt of "Prima" manpage:
172
173 Prima::Buttons - buttons and button grouping widgets
174
175 Prima::Calendar - calendar widget
176
177 Prima::ComboBox - combo box widget
178
179 Prima::DetailedList - multi-column list viewer with controlling header
180 widget
181
182 Prima::DetailedOutline - a multi-column outline viewer with controlling
183 header widget
184
185 Prima::DockManager - advanced dockable widgets
186
187 Prima::Docks - dockable widgets
188
189 Prima::Edit - text editor widget
190
191 Prima::ExtLists - listbox with checkboxes
192
193 Prima::FrameSet - frameset widget class
194
195 Prima::Grids - grid widgets
196
197 Prima::Widget::Header - multi-column header widget
198
199 Prima::ImageViewer - bitmap viewer
200
201 Prima::InputLine - input line widget
202
203 Prima::Label - static text widget
204
205 Prima::Lists - user-selectable item list widgets
206
207 Prima::MDI - top-level windows emulation classes
208
209 Prima::Notebooks - multipage widgets
210
211 Prima::Outlines - tree view widgets
212
213 Prima::PodView - POD browser widget
214
215 Prima::ScrollBar - scroll bars
216
217 Prima::Sliders - sliding bars, spin buttons and input lines, dial
218 widget etc.
219
220 Prima::TextView - rich text browser widget
221
223 In Prima, a tree-like menu is built by passing a nested set of arrays,
224 where each array corresponds to a single menu entry. Such as, to modify
225 the hello-world program to contain a simple menu, it is enough to write
226 this:
227
228 use Prima qw(Application MsgBox);
229 my $window = Prima::MainWindow-> new(
230 text => 'Hello world!',
231 menuItems => [
232 [ '~File' => [
233 ['~Open', 'Ctrl+O', '^O', sub { message('open!') }],
234 ['~Save as...', sub { message('save as!') }],
235 [],
236 ['~Exit', 'Alt+X', km::Alt | ord('x'), sub { shift-> close } ],
237 ]],
238 ],
239 );
240 run Prima;
241
242 Each of five arrays here in the example is written using different
243 semantics, to represent either a text menu item, a sub-menu entry, or a
244 menu separator. Strictly speaking, menus can also display images, but
245 that syntax is practically identical to the text item syntax.
246
247 The idea behind all this complexity is to be able to tell what exactly
248 the menu item is, just by looking at the number of items in each array.
249 So, zero or one items are treated as a menu separator:
250
251 [],
252 [ 'my_separator' ]
253
254 The one-item syntax is needed when the separator menu item need to be
255 later addressed explicitly. This means that each menu item after it is
256 created is assigned a (unique) identifier, and that identifier looks
257 like '#1', '#2', etc, unless it is given by the programmer. Here, for
258 example, it is possible to delete the separator, after the menu is
259 created:
260
261 $window-> menu-> remove('my_separator');
262
263 It is also possible to assign the identifier to any menu item, not just
264 to a separator. The other types (text,image,sub-menu) are discerned by
265 looking at the type of scalars they contain. Thus, a two-item array
266 with the last item an array reference (or, as before, three-item for
267 the explicit ID set), is clearly a sub-menu. The reference, as in the
268 example, may contain more menu items, in the recursive fashion:
269
270 menuItems => [
271 [ '~File' => [
272 [ '~Level1' => [
273 [ '~Level2' => [
274 [ '~Level3' => [
275 []
276 ]],
277 ]],
278 ]],
279 ]],
280 ],
281
282 Finally, text items, with the most complex syntax, can be constructed
283 with three to six items in the array. There can be set the left-aligned
284 text string for the item, the right-aligned text string for the display
285 of the hot key, if any, the definition of the hot key itself, and the
286 action to be taken if the user has pressed either the menu item or the
287 hot key combination. Also, as in the previous cases, the explicit ID
288 can be set, and also an arbitrary data scalar, for generic needs. This
289 said, the text item combinations are:
290
291 Three items - [ ID, text, action ]
292
293 Four items - [ text, hot key text, hot key, action ]
294
295 Five items - [ ID, text, hot key text, hot key, action ]
296
297 Six items - [ ID, text, hot key text, hot key, action, data ]
298
299 Image items are fully analogous to the text items, except that instead
300 of the text string, an image object is supplied:
301
302 use Prima qw(Application MsgBox);
303 use Prima::Utils qw(find_image);
304
305 my $i = Prima::Image-> load( find_image( 'examples/Hand.gif'));
306 $i ||= 'No image found or can be loaded';
307
308 my $window = Prima::MainWindow-> new(
309 text => 'Hello world!',
310 menuItems => [
311 [ '~File' => [
312 [ $i, sub {} ],
313 ]],
314 ],
315 );
316 run Prima;
317
318 The action item of them menu description array points to the code
319 executed when the menu item is selected. It is either an anonymous
320 subroutine, as it is shown in all the examples above, or a string. The
321 latter case will cause the method of the menu owner ( in this example,
322 the window ) to be called. This can be useful when constructing a
323 generic class with menu actions that can be overridden:
324
325 use Prima qw(Application);
326
327 package MyWindow;
328 use vars qw(@ISA);
329 @ISA = qw(Prima::MainWindow);
330
331 sub action
332 {
333 my ( $self, $menu_item) = @_;
334 print "hey! $menu_item called me!\n"
335 }
336
337 my $window = MyWindow-> new(
338 menuItems => [
339 [ '~File' => [
340 ['~Action', q(action) ],
341 ]],
342 ],
343 );
344
345 run Prima;
346
347 All actions are called with the menu item identifier passed in as a
348 string parameter.
349
350 Another trick is to define a hot key. While its description can be
351 arbitrary, and will be displayed as is, the hot key definition can be
352 constructed in two ways. It is either a literal such as "^A" for
353 Control+A, or @B for Alt+B, or "^@#F10" for Control+Alt+Shift+F10. Or,
354 alternatively, it is a combination of "km::" constants either with
355 ordinal of the character letter or the key code, where the key code is
356 one of "kb::" constants. The latter method produces a less readable
357 code, but is more explicit and powerful:
358
359 [ '~Reboot', 'Ctrl+Alt+Delete', km::Alt | km::Ctrl | kb::Delete, sub {
360 print "wow!\n";
361 }],
362 [ '~Or not reboot?', 'Ctrl+Alt+R', km::Alt | km::Ctrl | ord('r'), sub {}],
363
364 This concludes the short tutorial on menus. To read more, see
365 Prima::Menu .
366
368 The toolkit comes with a POD viewer program "podview" that can be
369 incorporated into an application. This is rather straightforward as you
370 can write the application manual in POD format.
371
372 • First, add some pod content to your main script, such as f ex:
373
374 #!/usr/bin/env perl
375 ...
376 =pod
377
378 =head1 NAME
379
380 My program
381
382 =cut
383
384 exactly as if you wanted "perldoc" to display it.
385
386 • Second, add an invocation code, possibly inside a menu:
387
388 ['~Help' => 'F1' => 'F1' => sub {
389 $::application-> open_help("file://$0|DESCRIPTION");
390 }],
391
392 "open_help" can also take a standard "L<link>" syntax so for
393 example
394
395 open_help("My::Module/help")
396
397 is also okay.
398
399 • Finally, consider if text-only POD is okay for you or you need
400 images embedded in the pod. This is somewhat tricky because the
401 perl maintainers actively reject the idea of having images in pod,
402 however metacpan.org can display images in the perl documentation
403 alright, and so does Prima, however both use different syntax.
404
405 Here is an example of a mixed content that will show graphic when
406 the graphic display is available, and just plain text otherwise:
407
408 =for podview <img src="illustration.gif" cut=1 title="Horizontal font measurements">
409
410 =for html <p>
411 <figure>
412 <img src="https://raw.githubusercontent.com/dk/Prima/master/pod/Prima/leadings.gif">
413 <figcaption>Horizontal font measurements</figcaption>
414 </figure>
415 <!--
416
417 .. plain text illustration ..
418
419 =for html -->
420
421 =for podview </cut>
422
423 GIF is chosen because Prima keeps all of its internal images into
424 this format, so it is a most safe fallback. However any other
425 format is okay too.
426
427 If you don't need a text fallback, just just this:
428
429 =for podview <img src="illustration.gif">
430
431 =for html <p><img src="https://raw.githubusercontent.com/me/myproject/master/illustration.gif">
432
434 Dmitry Karasik, <dmitry@karasik.eu.org>.
435
437 Prima
438
439
440
441perl v5.38.0 2023-07-21 pod::Prima::tutorial(3)