zecalc

 


Zecalc est une calculatrice sans clavier par Vincent Wartelle


A quoi peut bien servir une calculatrice sur un ordinateur, je me suis souvent posé la question. Vous aussi vous avez une vraie calculette à côté de votre clavier, non ?

Supposons-donc que vous n'en avez-pas.

Concernant une calculatrice sur ordinateur: faut-il vraiment qu'elle imite un clavier de calculatrice, dans la mesure ou votre ordinateur a un clavier ? Voici donc une calculatrice sans clavier. Comme l'est "bc" par exemple, si vous êtes unixien.

Précision pour les non-unixiens: un unixien est une personne qui sait ce qu'est "bc".


Zecalc est une calculatrice avec un historique


Par contre, qu'est-ce qu'une calculatrice sur ordinateur pourrait apporter de plus qu'une calculette basique ? La fonction qui m'a paru la plus évidente, c'est un historique illimité, qui peut faire office de mémoire. Dans une liste déroutante, vos calculs défilent, et vous pouvez les reprendre pour les modifier. Avec les flèches, ou avec la souris.

Le code source, en tcl/tk :

    #
    #	zecalc: une calculatrice avec historique
    #
    #	ce programme illustre une utilisation contemporaine ( en 2001 ) de tcl/tk
    #
    #   - protection des noms par le mécanisme des namespaces :
    #     toutes les variables sont propres à un espace de nommage
    #     nommé zecalc
    #   - orientation objet / composant grâce à des hashtables
    #     on peut créer autant de calculatrices que l'on veut
    #     	zecalc::_hist($id) est l'historique associée à la calculatrice $id
    #       zecalc::_value($id) est la valeur de calcul courante de $id
    #       zecalc::_msg($id) est le résultat ou message d'erreur de $id
    #	- compromis entre concision et documentation
    #     (110 lignes de code, 50 lignes de commentaire, 20 lignes blanches...)
    #
    #	programme écrit par Vincent Wartelle et la société oklin.com (tm)
    #   voir licence d'utilisation dans fichier d'aide.
    #
    namespace eval zecalc {
        variable _hist;
        variable _value;
        variable _msg;
    }

    #	constructeur de calculatrice
    #	chaque calculatrice sera identifiée par son chemin graphique
    proc zecalc::new { path } {
        variable _hist
        variable _value
        variable _msg

        # construction fenêtre mère
        if {[winfo exists $path]} {destroy $path}
        toplevel $path
        wm title $path "zecalc 1.0"
        wm geometry $path "-20+20"

        # initialise historique
        set _hist($path) {}

        # zone d'historique
        label $path.labhist -text "historique:"

        frame $path.hbox
        listbox $path.hbox.hist -listvar zecalc::_hist($path) -height 10	\
                -selectmode single -yscrollcommand "$path.hbox.sbar set"
        scrollbar $path.hbox.sbar -command [list $path.hbox.hist yview]
        pack $path.hbox.hist  -side left -expand true -fill both
        pack $path.hbox.sbar  -side right -expand true -fill y
        # sélectionner une ligne d'historique alimente la valeur avec cette ligne
        bind $path.hbox.hist <ButtonRelease> "zecalc::set_valuefromhistory $path"
        bind $path.hbox.hist <KeyPress-Return> "zecalc::set_valuefromhistory $path"

        # zone de calcul
        # et ses associations: touche entrée, flèche haute, flèche basse
        label $path.labexpr -text "calculer:"
        entry $path.xpres -textvariable zecalc::_value($path)
        bind $path.xpres <KeyPress-Return> "zecalc::eval $path"
        bind $path.xpres <KeyPress-Up> "zecalc::recall_up $path"
        bind $path.xpres <KeyPress-Down> "zecalc::recall_down $path"

        # zone de boutons
        frame $path.buttons
        button $path.buttons.calc -text "calculer" -command "zecalc::eval $path"
        button $path.buttons.help -text "aide" -command "zecalc::help $path"
        button $path.buttons.quit -text "quitter" -command exit
        pack $path.buttons.calc $path.buttons.help $path.buttons.quit \
                -side left -padx 5 -pady 5

        # bandeau du bas pour messages d'erreur
        label $path.msg -textvariable zecalc::_msg($path) -relief sunken -width 25

        # assemblage
        pack $path.labhist $path.hbox $path.labexpr $path.xpres \
                $path.buttons -side top -expand true -fill both
        pack $path.msg -side bottom -expand true -fill x
    }

    #	alimente la valeur de calcul depuis la ligne courante de l'historique
    proc zecalc::set_valuefromhistory { path } {
        variable _value
        set cursel [$path.hbox.hist curselection]
        if { $cursel == "" } { return }
        set _value($path) [$path.hbox.hist get $cursel ]
    }

    #	rapelle la valeur précédente de l'historique
    #	ou positionne sur la dernière ligne si l'historique n'était pas actif
    proc zecalc::recall_up { path } {
        set cursel [$path.hbox.hist curselection]
        if { $cursel == "" } {
            # attention!  la commande index de la listbox indique le numéro
            # qui suit la dernière valeur, il faut donc le décrémenter de 1
            set cursel [ expr [$path.hbox.hist index end] -1]
            $path.hbox.hist selection set $cursel $cursel
        } else {
            if { $cursel > 0 } {
                incr cursel -1
                $path.hbox.hist selection clear 0 end
                $path.hbox.hist selection set $cursel $cursel
                $path.hbox.hist see $cursel
            }
        }
        # copie dans la valeur courante
        zecalc::set_valuefromhistory $path
    }

    # 	rappelle la valeur suivante de l'historique
    #   (ou rien si l'on était pas dans l'historique ou en dernière ligne)
    proc zecalc::recall_down { path } {
        variable _value
        # récupère la sélection courante de la liste
        set cursel [$path.hbox.hist curselection]
        if { $cursel == "" } {
            return
        }
        set endcurs [ expr [$path.hbox.hist index end] -1]
        if { $cursel < $endcurs } {
            incr cursel
            $path.hbox.hist selection clear 0 end
            $path.hbox.hist selection set $cursel $cursel
            $path.hbox.hist see $cursel
            zecalc::set_valuefromhistory $path
        } else {
            $path.hbox.hist selection clear 0 end
        }
    }

    #	fonction de calcul à proprement parler
    #	c'est un encadrement de la fonction expr
    proc zecalc::eval { path } {
        variable _hist
        variable _value
        variable _msg

        # place dans l'historique le contenu de la zone de calcul
        # déselectionne l'historique; force à montrer la dernière ligne d'historique
        lappend _hist($path) $zecalc::_value($path)
        $path.hbox.hist selection clear 0 end
        $path.hbox.hist see end
        update

        # fonction de calcul
        #   l'évaluation est  [expr $zecalc::_value($path)]
        #	on multiplie cela par 1.0 pour forcer le calcul à faire en nombre réels
        #   catch intercepte les erreurs pour les placer dans zecalc::_msg($path)
        #	si la valeur entière du résultat est égale au résultat, on l'arrondit
        #	(supprime le .0)
        set res [ catch {set zecalc::_value($path) [expr 1.0 * $zecalc::_value($path)]} \
                zecalc::_msg($path) ]
        if { $res == 0 } {
            if { [expr int($zecalc::_value($path))] == $zecalc::_value($path) } {
                set zecalc::_value($path) [expr int($zecalc::_value($path))]
            }
        }
    }

    # 	écran d'aide
    proc zecalc::help { path } {
        set help "[set path]help"
        if {[winfo exists $help]} {
            destroy $help
        }
        toplevel $help
        wm title $help "aide - zecalc 1.0"
        wm geometry $help "-40+40"
        text $help.text -relief groove  -width 50 -height 12 -bg "SystemButtonFace" \
                -fg black -yscrollcommand "$help.sbar set"
        scrollbar $help.sbar -command "$help.text yview"
        button $help.quit -text "Fermer" -command "destroy $help"

        # ici, les composants sont assemblés en grille, à l'aide de grid
        # columnconfigure et rowconfigure autorisent le texte à s'étendre
        grid $help.text $help.sbar -sticky nsew
        grid $help.quit -padx 5 -pady 5
        grid columnconfigure $help 0 -weight 1
        grid rowconfigure $help 0 -weight 1

        # chargement de l'aide depuis un fichier
        # si le fichier n'est pas dans le répertoire courant
        # tentative d'accès au fichier placé "en bundle" grâce à freewrap
        set res [catch {set fd [open "zecalc1.txt" r]}]
        if {$res != 0 } {
            set res [ catch { set fd [open "/vincent/tcl/zecalc/zecalc1.txt" r]}]
        }
        if {$res != 0 } {
            $help.text insert 0.0 " le fichier d'aide zecalc1.txt n'a pas été trouvé "
        } else {
            set filecont [read $fd]
            $help.text insert 0.0 $filecont
            close $fd
        }
    }

    #	programme principal
    wm withdraw .
    zecalc::new .zecalc

Ce code source est à mon avis assez représentatif de ce que donne le langage tcl, dès que l'on dépasse le niveau "du bouton qui dit bonjour", et que l'on souhaite un minimum de structure pour permettre une éventuelle réutilisabilité. Toutefois, ce code source n'est pas non plus taillé pour un concours d'élégance, et il est certainement susceptible d'être amélioré.

Téléchargement : http://wfr.tcl.tk/fichiers/pub/zecalc1.tcl

Vous avez une petite notice d'utilisation http://wfr.tcl.tk/fichiers/pub/zecalc1.txt

La licence d'utilisation est une libre adaptation de la licence Artistique. (qui revendique que les informaticiens sont des artistes, donc).