Drag and Drop Notebook Tabs

CJB: An example of how to make drag and drop tabs with a ttk::notebook.


#Create notebook
set n [ttk::notebook .nb]
pack $n -fill both -expand 1

#Create tabs
foreach tab [list First Second Third] {
    set w [frame $n.[string tolower $tab]]
    label $w.src_lab -text "Clicked Tab Index:" -anchor e
    label $w.src_idx -textvariable src_index -width 3
    label $w.dst_lab -text "Released Tab Index:" -anchor e
    label $w.dst_idx -textvariable dst_index -width 3
    grid $w.src_lab $w.src_idx -sticky news
    grid $w.dst_lab $w.dst_idx -sticky news
    $n add $w -text $tab
}

#Bindings
bind all <KeyPress-question> {console show}
bind $n <ButtonPress>   [list click   %W %x %y]
bind $n <ButtonRelease> [list release %W %x %y]
bind $n <Motion>        [list motion  %W %X %Y]

#Sets index of tab clicked.
proc click   {W x y} {
    variable src_index [$W index @$x,$y]
    puts stderr "Clicked $src_index"
}

#Moves the tab to the position where it was dropped.
proc release {W x y} {
    variable src_index
    variable dst_index
    puts stderr "Released $src_index"
    #Check for a valid source
    if {[string is int -strict $src_index]} {
        set dst_index [$W index @$x,$y]
        #Check for a valid destination
        if {[string is int -strict $dst_index]} {
            set tab [lindex [$W tabs] $src_index]
            $W insert $dst_index $tab
            puts stderr "Insert $tab @ $dst_index"
        }
    }
}

#Passes mouse motion events to underlying widgets while dragging.
#Allows the notebook tabs to highlight on mouse-over.
proc motion  {W X Y} {
    set w [winfo containing $X $Y]
    if {$w ne $W && $w ne ""} {
        set x [expr {$X - [winfo rootx $w]}]
        set y [expr {$Y - [winfo rooty $w]}]
        event generate $w <Motion> -x $x -y $y
    }
}

peterc 2010-07-29: Looks good and it works well :) My only suggestion would be to change the cursor to a tab-like image during the drag (and change it back after button release) so the user has more visual feedback that they've picked up and are dragging the tab. Bonus points if you can include the tab title somehow :)


WJG (30/07/10) A similar behaviour is available with the gnocl::notebook widget. In addition to being able to reorganize widgets within a notebook, its also possible to drag and drop widgets within different notebooks in a common group.