Version 1 of label selection

Updated 2003-02-21 03:23:19

MGS Sometimes I want to be able to select the text in a label to paste into another application. So I wrote this little package to do just that. It wasn't as straightforward as I thought it might be, but at least I learned a few things about selection and the clipboard :-)

  # label.tcl --

  # Label selection.

  # You can double-click (Button 1) any label to set the selection to the
  # label's text. If a label can take focus (with the -takefocus option),
  # a single click (Button 1) will focus the label and then you can Cut,
  # Copy and Paste with <Control-x>, <Control-c> and <Control-v>.

  # Version   : 0.0.1
  # Author    : Mark G. Saye
  # Email     : [email protected]
  # Copyright : Copyright (C) 2003
  # Date      : February 20, 2003

  # ======================================================================

    namespace eval label {}

    package require Tk
    package provide label 0.0.1

  # ======================================================================

  proc label::button1 {W} {

    if { [string equal [$W cget -state] disabled] } { return }

    if { [$W cget -takefocus] } { focus $W }


  }

  # ======================================================================

  proc label::copy {W} {

    clipboard clear
    clipboard append [$W cget -text]

  }

  # ======================================================================

  proc label::cut {W} {

    copy $W

    if { ![string equal [$W cget -state] disabled] } {
      $W configure -text ""
    }

  }

  # ======================================================================

  proc label::paste {W} {

    if { [catch {clipboard get -displayof $W} clip] } {
      puts stderr "\[$::errorCode\] $clip"
      return
    }

    if { ![string equal [$W cget -state] disabled] } {
      $W configure -text $clip
    }

  }

  # ======================================================================

  proc label::focus:in {W} {

  }

  # ======================================================================

  proc label::focus:out {W} {

  }

  # ======================================================================

  proc label:handle {W offset maxChars} {

    return \
      [string range [$W cget -text] $offset [expr {$offset+$maxChars-1}]]

  }

  # ======================================================================

  proc label::normal {W} {

    # label has lost the selection - reset state to normal
    if { [string equal [$W cget -state] active] } {
      $W configure -state normal
    }

  }

  # ======================================================================

  proc label::select {W} {

    if { [string equal [$W cget -state] disabled] } { return }

    $W configure -state active

    selection own -command [list label::normal $W] $W

    selection handle -type UTF8_STRING $W [list label:handle $W]
    selection handle                   $W [list label:handle $W]

  }

  # ======================================================================

    bind Label <FocusIn>   [list label::focus:in  %W]
    bind Label <FocusOut>  [list label::focus:out %W]

    bind Label <<Copy>>    [list label::copy  %W]
    bind Label <<Cut>>     [list label::cut   %W]
    bind Label <<Paste>>   [list label::paste %W]

    bind Label <Double-1>  [list label::select  %W]
    bind Label <Button-1>  [list label::button1 %W]

    bind Label <Control-x> [list event generate %W <<Cut>>]
    bind Label <Control-c> [list event generate %W <<Copy>>]
    bind Label <Control-v> [list event generate %W <<Paste>>]

  # ======================================================================

  # demo code

  proc main {{argc 0} {argv {}}} {

    entry  .e
    .e insert end "Entry - Hello World"

    label .l1 -text "Label Without Focus"

    label .l2 -text "Label With Focus" \
      -takefocus 1 \
      -highlightthickness 1 \
      -relief sunken -bd 1

    global state
    set state [.l2 cget -state]

    foreach _state {normal active disabled} {
      set r .$_state
      radiobutton $r \
        -text $_state \
        -variable state \
        -value $_state \
        -command [list .l2 configure -state $_state]
    }

    button .b -text Close -default active -command exit

    pack .b        -side bottom -anchor se
    pack .e        -side top    -expand 0 -fill x -padx 20 -pady 20
    pack .l1       -side top    -expand 0 -fill x -padx 20 -pady 20
    pack .l2       -side top    -expand 0 -fill x -padx 20 -pady 20
    pack .normal   -side top    -expand 0 -fill x
    pack .active   -side top    -expand 0 -fill x
    pack .disabled -side top    -expand 0 -fill x

  }

  # ======================================================================

    if { [info exists argv0] && [string equal [info script] $argv0] } {
      main $argc $argv
    }


  # ======================================================================

KBK A very pretty discussion of bindings and clipboard management. Nevertheless, most of us prefer an entry or text with -state disabled for implementing a UI component that supports selection but not modification. Mark G. Saye