Tk. Een introductie.

ArticleCategory:

Software Development

AuthorImage:

[Photo of the Author]

TranslationInfo:

Original in fr Charles Vidal

fr to en Charles Vidal

en to nl Tom Uijldert

AboutTheAuthor:

Baas van een gastronomisch tentje in Parijs. Gecharmeerd door GNU en de filosofie van Open Source omdat ze mensen kennis laten delen. Hij zou wat meer tijd aan zijn saxofoon willen besteden.

Abstract:

Dit artikel gaat in op de grafische hulpmiddelen van Tcl, te weten: Tk. We zullen demonstreren hoe eenvoudig het is een grafische toepassing hiermee in elkaar te zetten, met gebruikmaking van slechts enkele regels code.

ArticleIllustration:

[Illustratie]

ArticleBody:

Tk, de grafische hulpmiddelen voor Tcl: WISH

Tk is speciaal gemaakt om Tcl grafische mogelijkheden te geven. Dit noemen we doorgaans Tcl/Tk (spreek uit: tikkel/tiekee).

Tk is een grafische omgeving, geschikt voor meerdere machines maar met hetzelfde uiterlijk als het lokale operating systeem. Een ideale combinatie met Tcl, dat ook geschikt is voor meerdere machines. Groot voordeel van Tcl/Tk is de eenvoud. Het duo stelt je in staat snel applicaties te maken die je op meerdere omgevingen in kunt zetten. Net zoals er een tclsh is voor Tcl is er een wish voor Tk.

Hello world !

Als voorbeeld zal ik een klassiek programma tonen dat de eenvoud en mogelijkheden van een implementatie in Tcl/Tk illustreert (het spreekt Frans).
pack [ label .l -text "Bonjour monde" ]

Vergelijk dat eens met een gtk programma dat in C is geschreven:
#include <gtk/gtk.h>
Int main( int   argc,
          char *argv[] )
{
   /* GtkWidget is the storage type for widgets */
    GtkWidget *window;
    GtkWidget *button;

    gtk_init(&&argc, &&argv);
   /* create a new window */
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    button = gtk_button_new_with_label ("Bonjour Monde");
    gtk_container_add (GTK_CONTAINER (window), button);
    gtk_widget_show (button);

    /* and the window */
    gtk_widget_show (window);
    gtk_main ();

    return(0);
}
...of met Motif
/* COMPILE  cc xmhello.c -L/usr/X11R6/lib  -lXm -lXt -lX11 -lXmu -o xmhello */

#include <Xm/PushB.h>
#include <Xm/Form.h>

/* Widget */

	Widget      main_widget, pushb;

main(int argc, char **argv)
{
	Widget      form;
	Arg         args[1];
	int         ac = 0;
	XmString    label_str;

	main_widget = XtInitialize(argv[0], "test", NULL, 0, &&argc, argv);
	label_str = XmStringCreate("Bonjour Monde", XmSTRING_DEFAULT_CHARSET);
	XtSetArg(args[ac], XmNlabelString, label_str);
	ac++;
	pushb = XmCreatePushButton(main_widget, "hello", args, ac);
	XtManageChild(pushb);
	XtRealizeWidget(main_widget);
	XtMainLoop();
}
Maar het is niet eenvoudig om de code van een scripttaal te vergelijken met die van een gecompileerde. We moeten hierbij ook andere aspecten betrekken zoals het geheugengebruik van de totale applicatie. Het enige wat we hier dus kunnen concluderen is dat het maken van het klassieke "Hello World" programma in Tk een makkie is. We kunnen beter kijken naar het concept en de ideeën van de hulpmiddelen in plaats van naar het uiterlijk.
Er zijn een aantal uitbreidingen op deze hulpmiddelen om het uiterlijk van de Tk- widget te veranderen, bijvoorbeeld Qtk en TkStep.
Verder is het interessant te weten dat de Tk hulpmiddelen kunnen worden gecombineerd met een groot aantal andere talen. En zoals een hoop andere scripttalen is Tcl/Tk beschikbaar op meerdere platformen.

Het creëren van een grafisch object in Tk

Tk levert een aantal standaard te gebruiken grafische objecten (widgets) waarmee je een grafische omgeving voor je applicatie kunt maken. Ga voor een demo van alle beschikbare widgets naar de directory /usr/local/lib/tk8.0/demos en start daar widget.

Het aantal grafische objecten is beperkt (er zijn geen tree widgets, combo boxes enz.). Een aantal personen en bedrijven echter hebben waardevolle uitbreidingen hierop uitgebracht. De meest bekende hiervan is Tix, de widgets Incr Tcl en meest recentelijk het mooie BWidget. Al deze uitbreidingen zijn te verkrijgen bij scriptics.

De boomstructuur van het grafische object

Een grafische omgeving wordt opgebouwd als een boom met vensters (windows) met ieder hun eigen karakteristieken.
Bladeren aan een dergelijke boomstructuur zijn de dumpplaats voor karakteristieken van grafische objecten zoals bijvoorbeeld een button. Een boomstructuur wordt in Tcl/Tk als volgt beschreven: Als wish wordt gestart verschijnt er een venster. Dit is het root-venster met de naam . (punt).

Het aanmaken van grafische objecten: "Hello world"

Het commando voor het aanmaken van een grafisch object in Tcl ziet er als volgt uit: naam_object.(naam_dumpplaats)*naam_grafisch_object[karakteristiek waarde]

Voorbeeld: label .mylabel -text "hello world"

Zoals je kunt zien wordt de actie geïnitieerd door de naam op te geven van het object dat moet worden gecreëerd, hier .label genaamd, vervolgens de naam van de dumpplaats, waarvan . het root-venster is en op het eind geef je de karakteristieken (-text "hello world"). Merk op dat je op ieder moment de argumenten en dus de karakteristieken van het object na het aanmaken kunt veranderen.

En nu heeft het label de tekst "Bonjour monde in french :)"
Dit kan worden weergegeven met het commando: puts [label .mylabel -text "hello world"].
Het label kan het resultaat van een commando weergeven:
.mylabel configure -text "Dit is de datum [ exec date ]"
Om de opties te laten zien die je aan configure mee kunt geven voor een bepaalde widget kun je het volgende intikken: ".mylabel configure", interactief in wish. Je krijgt dan een foutmelding en een lijst van opties die je mee kunt geven.

Opmaak: Plaatsen van widgets

Mogelijk merk je nu op "Er gebeurt niets, ik krijg niets te zien op het scherm".

Inderdaad, je hebt net een object aangemaakt van het label-type maar je hebt niet gevraagd om het ook weer te geven. Dat is omdat voor het weergeven nog meer informatie nodig is die je niet hebt gegeven, namelijk de opmaak (de opmaak bepaalt het plaatsen of positioneren van vensters) die voor dit object geldt.

Hier de mogelijke opmaken:

  1. De packer
  2. De placer
  3. De grid
Laten we hiervan de eenvoudigste nemen, de packer. Deze voegt het object aan zichzelf toe volgens de opgave van de gebruiker. Later meer hierover.

Een meer volledig hello world programma

label .mylabel -text "hello world"
pack .mylabel
Of, in 1 regel:
pack [label .mylabel -text "hello world"]
De button. Laten we deze eens bekijken:
button .mybutton -text "hello world" -command "exit"
pack  .mybutton 
Merk op dat de button een command-karakteristiek heeft als argument (slechts één). Dit is het te executeren tcl-commando als de gebruiker deze button aanklikt. In dit voorbeeld is het betreffende commando exit, wat het programma laat stoppen.

Variabelen aan grafische objecten koppelen

De kracht van Tcl/Tk zit hem vooral in het vermogen om variabelen aan grafische objecten te koppelen voor het registreren van statusveranderingen in het object. We hoeven geen functie aan te roepen om de toestand van een object te bepalen. Vice versa zal een verandering in de variabele een zelfde verandering in het geassocieerde object teweegbrengen. Het moge duidelijk zijn dat dit het programmeren sterk vereenvoudigt en tot minder code leidt.

Voorbeeld

De checkbuttons en radiobuttons

  1. Een checkbutton vertegenwoordigt een bepaalde toestand.
    Dit is een binaire (booleaanse) toestand (aan of uit). We kunnen hieraan een variabele koppelen die standaard de waarde 0 heeft of 1, in overeenstemming met de toestand van de checkbutton. We kunnen de waarde van de variabele ook definiëren, afhankelijk van de toestand van de checkbutton.
    Voorbeeld:
    checkbutton $w.b1 -text "Wipers OK" -variable wipers -relief flat  -onvalue "Ok" -offvalue "not Ok"
    
  2. Een radiobutton duid op de toestand van meerdere buttons (een set buttons.)
    Radiobuttons zijn meestal gegroepeerd, waardoor je slechts één button van de set kunt kiezen. Voor dit groeperen moet je dezelfde variabele aan meerdere buttons koppelen en de waarde van de variabele bepalen wanneer de betreffende button wordt geselecteerd.
    Voorbeeld:
    radiobutton .b1 -text "Een " -variable size -value 1
    radiobutton .b2 -text "Twee " -variable size  -value 2
    
Entry
Dit is een regel tekst die de gebruiker zelf in kan vullen. Hieraan kan een variabele worden gekoppeld met de optie -textvariable.
Voorbeeld:
entry .e  -textvariable toto  -width 40 

Opmaakmethode

Meestal worden grafische objecten in een frame (omlijsting) geplaatst. Kijk uit dat je slechts één opmaakmethode toepast voor een frame. Er zijn drie opmaakmethodes:
  1. De packer. Positioneert het object vanaf een oriëntatiepunt:
    1. top (boven)
    2. bottom (onder)
    3. right (rechts)
    4. left (links)
    Voorbeeld:
    pack [ button .b1 -text top ] -side top
    pack [ button .b2 -text bottom ] -side bottom
    pack [ button .b3 -text right ] -side right
    pack [ button .b4 -text right ] -side left
    
    We kunnen ook de manier van vergroten van het widget van binnenuit bepalen met de optie: -expand (yes|no) -fill (x|y|both)
  2. De placer. Deze plaatst het object op de opgegeven x y positie.

    Voorbeeld: place [ label .l -text "Avec Place"] -x 100 -y 100 .l configure -bg red

  3. De grid plaatst widgets op een virtueel rooster bestaande uit rijen en kolommen. Het is de ideale opmaak voor listboxes en meerregelige editboxes. De syntaxis hiervoor: creëer eerst de widgets, bijvoorbeeld .e_name en geef deze vervolgens weer met:

    label .mainlbl2 -text "Label 2" -bd 2 -relief sunken
    grid .mainlbl2 -row 0 -column 1 -sticky news
    label .mainlbl1 -text "Label 1" -bd 2 -relief raised
    grid .mainlbl1 -row 0 -column 0 -sticky news
    label .mainlbl3 -text "Label 3" -bd 2 -relief solid
    grid .mainlbl3 -row 1 -column 0
    label .mainlbl4 -text "Label 4" -bd 2 -relief groove
    grid .mainlbl4 -row 1 -column 1

Een overzicht van gecreëerde widgets

Het commando winfo geeft ons dit overzicht:
winfo exists name_object
We kunnen het overzicht krijgen van alle widgets met:
winfo children .
Deze functionaliteit kun je niet vinden in andere gecompileerde hulpmiddelen (gtk, wt, Motif ...).

Events

Tk handelt een gebeurtenis af en voert het commando uit als de -command optie mee werd gegeven. Er zijn gevallen waarin je dit met meer detail af wilt handelen of wanneer je meerdere gebeurtenissen voor een widget wil afhandelen. Het canvas is hier een voorbeeld van.
bind naam_widget naam_event tcl_code.

Een klein voorbeeld

We gaan een grafische applicatie maken die de inhoud van een .tar (al dan niet ook nog .gz) bestand laat zien.
De afhandeling bestaat uit een lijst met twee scrollbars.
Hier is een beschrijving van de structuur van het script:
  1. We bouwen de grafische afhandeling (proc makegui)
  2. We voeren alle paden van het widget in in een hash-tabel tabgui
  3. We onderzoeken het aantal meegegeven argumenten. Als dit nul is dan stopt het programma.
  4. We openen de handle vanuit een pipe met het programma tar -tzvf naam_tar_bestand.
  5. We voegen iedere regel die we uit de pipe lezen toe aan de lijst.
We detecteren een eventuele "Control-C" toetscombinatie om het programma te beëindigen.
bind all <Control-c> {destroy .}
Dit is slechts een klein voorbeeld, voor verbetering vatbaar. We kunnen testen of het bestand gecomprimeerd is of niet met het tcl-commando string first. Als de gebruiker geen argument meegeeft kunnen we een venster maken van waaruit we het betreffende bestand kunnen selecteren (file chooser). We kunnen wat finesse toevoegen door een popmenu te maken, waarmee de gebruiker bestanden uit de lijst kan manipuleren. Tenslotte kunnen we boven nog een menubalk toevoegen waarmee de gebruiker een nieuw bestand kan openen, een nieuw archief creëren...
#!/bin/sh
# the next line restarts using wish \
exec wish8.0 "$0" "$@"

global tabgui

proc makegui { } {
global tabgui
#
# Creation of the  scrollbars for the list
# then the horizontal scrollbar is placed right, filling up horizontally the window
# and the vertical scrollbaris placed below, filling up vertically the window
#
set tabgui(scrollv) [scrollbar .scrollv -command ".list yview"]
pack $tabgui(scrollv) -side right -fill y
set tabgui(scrollh) [scrollbar .scrollh -command ".list xview" -orient horizontal ]
pack $tabgui(scrollh) -side bottom -fill x
#
# Creation of the list associating it to the scrollbar
#
#
set tabgui(list) [listbox .list  \
                -yscroll "$tabgui(scrollv) set" \
                -xscroll "$tabgui(scrollh) set" \
                -relief sunken -width 20 -height 20 \
        -setgrid yes ]
pack $tabgui(list) -side left -fill both -expand yes
wm minsize . 1 1
}

#
# Creation of the GUI
#
makegui

if $argc>0 {set tarfile [lindex $argv 0]} else {puts stderr "tar file missing" ; exit} 
set command "tar -tzvf $tarfile"
set tube [ open |$command r] 
 while {![eof $tube]} {
    set tarresult  [ gets $tube ] 
    $tabgui(list)  insert end $tarresult
}

bind all <Control-c> {destroy .}

Bronnen