next up previous contents
Next: References Up: 3 Custom Programming Previous: 3.5 Common Fx settings

3.6 Putting it all together


After you have a feeling for the Fx interfaces, it's easy to put together nice applications in a jiffy. As an example, let's add some custom features to our little Invoices application.

One useful function for invoices might be an auto-increment invoice number with a prefix, say ``HPC''. We would like to add a unique invoice number each time we add a new record, so we might add the following to our QddbScript:

;# ...
[code value={
    ;# implements autoincrement by 123, starting at 1000000, with
    ;# a prefix of "HPC".
    proc MyInvoiceNumber {prefix min increment} {
        global gv_attr
        set filename [qddb_schema path [menubar cget -schema]]/.nextinv
        if {[catch {open $filename r+} fd] != 0} {
            set next $min
            if {[catch {open $filename w+} fd] != 0} {
                Fx:Dialog .dialog "Cannot open $filename"
            qddb_util flock $fd LOCK_EX
        } else {
            qddb_util flock $fd LOCK_EX
            set next [read $fd]
        set gv_attr(Number) "$prefix$next"
        incr next $increment
        seek $fd 0 start ;# rewind to beginning of file
        puts -nonewline $fd $next
        flush $fd
        qddb_util flock $fd LOCK_UN
        close $fd
    menubar configure -afteraddmode {
        MyInvoiceNumber HPC 1000000 123
;# ...

Next, we might like to recalculate subtotal, tax, and total each time these fields change. For this purpose, it makes sense to perform the calculations each time the focus leaves one of the important fields:

;# ...
[code value={
    proc Recalculate {} {
        global fx:mode_variable myview

        if {"${fx:mode_variable}" != "Add Mode"} {
        set tuple [menubar cget -tuple]
        set view [qddb_view define $tuple {
            {Items.Qty myview(Items.Qty)}
            {Items.Taxable myview(Items.Taxable)}
            {Items.Price myview(Items.Price)}
            {Items.Total myview(Items.Total)}
            {Subtotal myview(Subtotal)}
            {Tax myview(Tax)}
            {AmountDue myview(AmountDue)}
            {PaymentAmount myview(PaymentAmount)}
            {Discounts myview(Discounts)}
            {Total myview(Total)}
        set max [qddb_instance maxnum $view Items]
        set myview(Tax) 0.00
        set myview(Subtotal) 0.00
        set myview(Total) 0.00
        for {set i 1} {$i <= $max} {incr i} {
            qddb_instance switch $view Items $i
            catch {
                set myview(Items.Total) [expr \
                    $myview(Items.Qty) * $myview(Items.Price) \
	        set myview(Subtotal) [expr $myview(Subtotal) \
                    + $myview(Items.Total)]
                if {"$myview(Items.Taxable)" != "N"} {
                    set myview(Tax) [format "%.2f" [expr $myview(Tax) \
                        + ($myview(Items.Total) * 0.06)]]
        catch {
            set myview(Total) [expr $myview(Subtotal) + \
                $myview(Tax) - $myview(Discounts)]
        set myview(AmountDue) [expr $myview(Total) - $myview(PaymentAmount)]
        ;# force GUI to re-read variables
        qddb_view refresh [menubar cget -view]
        update idletasks
        qddb_view delete $view
        unset myview
    bind Entry <FocusOut> {+Recalculate}
    bind Radiobutton <FocusOut> {+Recalculate}
;# ...

You can retrieve a full copy of this QddbScript and the associated Schema from To try it out, simply unpack the archive in a newly created database directory.

    qnewdb Invoices
    cd Invoices
    gunzip -c ~/QddbScript-example.tar.gz | tar -xvf -
    nxqddb .


The Qddb Team

Herrin Software Development, Inc.