A SQLite table widget

Sarnold: Here is a mega-widget which works together with the Object-oriented SQLite wrapper.

package require Tk
package require tableview_sql
package provide tableview 0.1

namespace eval tableview {
        class create tableview {
                constructor {hullname sql tbl} {
                        my variable hull 
                        set hull $hullname
                        my variable table 
                        set table [tableview::table create $hullname.table $sql $tbl]
                        my variable columns 
                        set columns ""
                        my variable height
                        my variable start
                        set height 10
                        set start 1
                        toplevel $hull
                }
                # for debugging purposes
                method delegate {args} {
                        my variable table
                        $table {*}$args
                }
                method column {sub args} {
                        my column_$sub {*}$args
                }
                method column_add {name args} {
                        my variable table
                        my variable columns
                        set options [$table column info options]
                        set myoptions {-width -title}
                        dict set columns $name ""
                        set sql [list $table column add $name]
                        foreach {opt val} $args {
                                if {$opt in $options} {
                                        lappend sql $opt $val
                                } elseif {$opt in $myoptions} {
                                        dict lappend columns $name $opt $val
                                } else {
                                        error "unknown option $opt"
                                }
                        }
                        eval $sql
                }
                method draw {args} {
                        my variable height
                        my variable hull
                        set height [tableview::default $args -height $height]
                        set title [tableview::default $args -title "SQL data"]
                        wm title $hull $title
                        my variable columns
                        foreach col [dict keys $columns] {
                                pack [frame $hull.$col] -side left
                                label $hull.$col.title -text [tableview::default [dict get $columns $col] -title $col]
                                pack $hull.$col.title -side top
                                for {set i 0} {$i < $height} {incr i} {
                                        pack [label $hull.$col.row$i -text ""] -side top
                                }
                        }
                        pack [scrollbar $hull.scrolling -command [list [self] yview]] -side left
                        my redraw
                        my sync_scrolling
                }
                
                method sync_scrolling {} {
                        my variable start
                        set len [my delegate length]
                        if {$len == 0} {return}
                        if {$start > $len} {
                                # rows have been removed under the cursor
                                set start 1
                                my redraw
                                my sync_scrolling
                                return
                        }
                        my variable hull
                        my variable height
                        $hull.scrolling set [expr {double($start-1)/$len}] [expr {min(1.,double($start+$height-1)/$len)}]
                }
                
                method yview {sub args} {
                        my variable start
                        set start [my yview_$sub {*}$args]
                        my sync_scrolling
                }
                method yview_moveto {fraction} {
                        my redraw [expr {[my delegate length]*$fraction}]
                }
                method yview_scroll {number type} {
                        my yview_scroll_$type $number
                }
                method yview_scroll_units {n} {
                        my variable start
                        my variable height
                        set len [my delegate length]
                        if {$len < $height || $start+$n<1} {return [my redraw]}
                        if {$n > 0} {
                                if {$start+$n > $len-$height+1} {
                                        return [my redraw [expr {$len-$start-$height+1}]]
                                }
                                return [my redraw [expr {$start + $n}]]
                        }
                        my redraw [expr {$start+$n}]
                }
                method yview_scroll_pages {n} {
                        my variable height
                        my yview_scroll_units [expr {$n*($height-1)}]
                }
                
                method redraw {{mystart 1}} {
                        my variable start
                        my variable height
                        my variable table
                        my variable columns
                        my variable hull
                        set mystart [expr {round($mystart)}]
                        set names [dict keys $columns]
                        set end [expr {min($height+$mystart-1,[$table length])}]
                        puts $mystart,$end
                        set data [$table get range $mystart $end]
                        for {set i 0} {$i < [llength $data]} {incr i} {
                                set row [lindex $data $i]
                                foreach name $names {
                                        $hull.$name.row$i configure -text [dict get $row $name]
                                }
                        }
                        return $mystart
                }
        }
}

Usage:

sqlite3 db my.db
tableview::tableview create tbl .tbl db emp
tbl column add emp_name -key yes
tbl column add emp_age -type integer
tbl draw