Monday, January 04, 2010

Gnocl Tutorial #1 -The Basics

The whole idea behind developing the Gnocl Tcl package is to make to process of developing Gtk+/Compliant applications easy to develop. Ordinarily, creating a Gtk+ application requires not only a good understanding of the C programming language and its build tools, but also practical familiarity with the innards of the various Gtk+
libaries.

The Tcl scipting language was designed to isolate (or spare) the scripter from the daunting task of negotiating the vast array of build libraries and needed to get event the most simplest of task-driven applications to work, gnocl does the same. Unlike other bindings such as PyGtk which places a 'wrapper' around Gtk libraries making them accesible to the script, such an approach still requires the scripter to understandin the innards of the Gtk libraries. For the newcomer, the big-jump into
developing useful code is less than programming directly in C, but still a lengthy task when compare to the directness of the Gnocl approach.

So, how does Gnocl work? The idea is to maintain the tool-command paradigm that forms the heart of Tcl and it companion package, Tk. Here a glimpse at a first application would be useful. As were running under some form of *nix, we need to open a script file and enter the following lines.

#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"

package require Gnocl

Save this as script1.tcl. At the command prompt, change the persmissions of the file to get the schell to run the script as an executable. To do this, simply run:

chmod +x *.tcl

Then run, using

./script1.tcl

Assuming, that we've already successully installed Tcl and the Gnocl packages, this will produce absolutely nothing on screen! In fact, this is good. It tells that all the packages are properly installed. Now add the following line of code, save and re-run.

gnocl::window

Voila! The window is now open. This one line of script provides the scripter with a whole raft of pre-porgrammed options. Ranging from event handling, style settings and even compositing to screen with a bitmask. This, is he beauty of the Tcl approach. Lets now create a button. We can add the following line, just above the gnocl::window command.

set but1 [gnocl::button -text "Hello World!" -onClicked {puts "Hello World"} ]

This simple command look straightforward to understand. Widget options are set in a way familiar to anyone with exposure to using console based applications. The global variable 'but1' needs to be set, so that the script can directly handle the new widget. To tell the system to add the button as the 'child' of the window 'parent', modify the gnocl::window line to read:

gnocl::window -child $but1

But, just for fun, also add the following extra options to set the title of the window, change its size and what to do when the close button is clicked.

gnocl::window \
    -child $but1 \
    -title "My First Gnocl App" \
    -onDestroy {exit} \
    -widthRequest 320 \
    -heightRequest 200 

Here's the full listing:

# script1.tcl
#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"

package require Gnocl

set but1 [gnocl::button \
    -text "Hello World!" \
    -onClicked {puts "Hello World"} ]

gnocl::window \
    -child $but1 \
    -title "My First Gnocl App" \
    -onDestroy {exit} \
    -widthRequest 320 \
    -heightRequest 200

As can be seen, a single line of script can be quite long and dificult to read. Unlike other scripting languages which are quite 'fixed' in their formatting, Tcl is flexible. To break commands over multiple lines simple add '\'. This will tell the Tcl interpreter that that next line is still a part of the current command.

This is about the simplest application that can be made. But, what if we want to add more widgets? A toplevel window has only one child, the choice of its child is important. In order to add more widget What we need to first add a container -- a gnocl::box. The next script illustrates this point.

# script2.tcl
#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"

package require Gnocl

set but1 [gnocl::button \
    -text "Hello World!" \
    -onClicked {puts "Hello World"} ]

set but2 [gnocl::button \
    -text "Good Morning!" \
    -onClicked {puts "Good Morning"} ]

set box [gnocl::box -children "$but1 $but2" ]

set but3 [gnocl::button \
    -text "Good Afternoon!" \
    -onClicked {puts "Good Afternoon"} ]

$box add $but3

gnocl::window \
    -child $box \
    -title "My First Gnocl App" \
    -onDestroy {exit} \
    -widthRequest 320 \
    -heightRequest 200

Here we can see that but2 was created and added directly to the box at initialisation. As the -children option can take more than one value, we sent a list of values which, in this case are strings containing the names of the buttons previously created. A third button, but3 is created later which then added to the list of children.

So far, we have made some pretty large buttons. Resizing the window will, of course, resize the child widgets it contains; in gnocl-ese the widgets are 'filling' their parent, and 'expanding' as the toplevel window that contains them all is resized. As  might be expected, both '-fill' and '-expand' are switchable options. To best demonstrate this feature, lets work with an alternative version of script2.tcl,

# script3.tcl
#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"

package require Gnocl

set but1 [gnocl::button \
    -text "Hello World!" \
    -onClicked {puts "Hello World"} ]

set but2 [gnocl::button \
    -text "Good Morning!" \
    -onClicked {puts "Good Morning"} ]

set but3 [gnocl::button \
    -text "Good Afternoon!" \
    -onClicked {puts "Good Afternoon"} ]

set box [gnocl::box ]

$box add $but1 -fill {0 0} -expand 0
$box add $but2 -fill {1 1} -expand 1
$box add $but3 -fill {0 0.5} -expand 1

gnocl::window \
    -child $box \
    -title "My First Gnocl App" \
    -onDestroy {exit} \
    -widthRequest 320 \
    -heightRequest 200

Running this script and resizing the window will show some interesting behaviours; but1 always remains the same size, but2 will expand to fill whatever space is available, whereas but3 does not change its width but only its height to fill half (i.e 0.5) of its available space. Clearly, the script is controlling what proportion of the window display space will be occupied by a widget. This is achieved by providing a 'fill factor' between 1 and zero. In most instances, however, these will typically be either 0 or 1. The -expand switch, by the way is a boolean, that means either a yes (1) or no (0) option.


Reblog this post [with Zemanta]

No comments: