Updated 2018-09-15 20:13:59 by vancan1ty

Documentation for ttk::combobox edit

Ttk's combobox widget.
https://www.tcl.tk/man/tcl/TkCmd/ttk_combobox.htm

Question edit

Actually, this so-called "combobox" is a "drop-down box". Is there a real combobox available, consisting of an entry combined with a listbox? Just like the font chooser in the format/character dialog of LibreOffice - and as opposed to the font chooser in the toolbar of LibreOffice? Wikipedia also gives a good description of it: https://en.wikipedia.org/wiki/Combo_box

EMJ 2017-01-12 - Was this ever true? It isn't now.

Ideas for combobox autocompletion edit

TR - I saw that the combobox of the Tile package didn't support autocompletion, so I added it using the code from BWidget:
proc ComboBoxAutoComplete {path key} {
        #
        # autocomplete a string in the ttk::combobox from the list of values
        #
        # Any key string with more than one character and is not entirely
        # lower-case is considered a function key and is thus ignored.
        #
        # path -> path to the combobox
        #
        if {[string length $key] > 1 && [string tolower $key] != $key} {return}
        
        set text [string map [list {[} {\[} {]} {\]}] [$path get]]
        if {[string equal $text ""]} {return}
        
        set values [$path cget -values]
        set x [lsearch $values $text*]
        if {$x < 0} {return}
        
        set index [$path index insert]
        $path set [lindex $values $x]
        $path icursor $index
        $path selection range insert end
}

All you need to do now, is binding <KeyRelease> to this procedure:
package require Tk 8.5
package require tile
ttk::combobox .c -values [list one two three four five six seven]
pack .c -padx 5 -pady 5
bind .c <KeyRelease> [list ComboBoxAutoComplete .c %K]

CLN 2006-04-20 - Shouldn't this be in a namespace or at least be named ttkComboBoxAutoComplete? For that matter, why not submit a patch to get this into the Tile distribution. (Not that I wouldn't be grateful to have it available here in the mean time if I was using Tile.)

TR 2006-04-21 - I just read the tile paper [1] by Rolf Ade. It mentions autocompletion code in the demos directory of the tile distribution. I haven't used that code yet, but it seems to do the same job as the code above, just in the correct namespace and as a command like
 tile::combobox::enableAutocomplete

So, the above code is not needed, really ...

Googie Aug 6, 2011 - Note, that at the current moment there's no
 tile::combobox::enableAutocomplete

so the code above makes sense again. Just a small suggestion would be to support case-insensitive autocompletion. To accomplish this with above code just modify the "lsearch" line to look like this:
 set x [lsearch -nocase $values $text*]

Googie Aug 6, 2011 - In addition to autocompletion, the preselection of item from list that is already dropped down using the key for first letter:
proc ComboListKeyPressed {w key} {
        if {[string length $key] > 1 && [string tolower $key] != $key} {
                return
        }

        set cb [winfo parent [winfo toplevel $w]]
        set text [string map [list {[} {\[} {]} {\]}] $key]
        if {[string equal $text ""]} {
                return
        }

        set values [$cb cget -values]
        set x [lsearch -glob -nocase $values $text*]
        if {$x < 0} {
                return
        }

        set current [$w curselection]
        if {$current == $x && [string match -nocase $text* [lindex $values [expr {$x+1}]]]} {
                incr x
        }

        $w selection clear 0 end
        $w selection set $x
        $w activate $x
        $w see $x
}

bind ComboboxListbox <KeyPress> [list ComboListKeyPressed %W %K]

To use it, just drop down the list of values in combobox and press letters according to first characters in available values. If there's more than one item starting with pressed key, then next item with matching name is selected for each key press.

jnc Feb 5, 2010 - Here is complete auto-complete code. This code completes while in an editable or readonly combobox. It also completes the with a key press when in the drop down list from the combobox. At the bottom is a simple example.

jnc Sep 15, 2010 - Updated coded... In a read only widget pressing S will match "Six" and pressing S again will match the next "S" entry which is "Seven" in my example. When no more matches are found, it will start back at the beginning "Six". This is behavior as found in Windows and suggested by MHo. Also bug fixes to some keys such as ' and ".

The code is getting large enough it does not belong mixed in which a lot of other code on the page. Please see my Misc Tcl Repository http://jeremy.cowgar.com/misctcl/index.cgi/index and the combobox code is specifically located at: http://jeremy.cowgar.com/misctcl/index.cgi/doc/tip/combobox/combobox.tcl

[vancan1ty] Sep 15, 2018 note -- the links above are now dead. However I found Jeremy Cowgar's combobox code on github here: https://github.com/jcowgar/misctcl/blob/master/combobox/combobox.tcl .

rz Apr 6, 2016 - another autocompletion code attempt.
# Combobox enhancement: select item with typing
bind ComboboxListbox <KeyPress>         { ::ttk::combobox::Autoselect %W %A}
bind ComboboxListbox <Key-Delete>        { ::ttk::combobox::Autoselect %W {}}
bind ComboboxListbox <Key-BackSpace>         { ::ttk::combobox::Autoselect %W {}}
set ::ttk::combobox::Autoselect {}
proc ::ttk::combobox::Autoselect {w key} {
  variable Autoselect
  if {$key eq {}} {
    set Autoselect [string range $Autoselect 0 end-1]
  } else {
    append Autoselect $key
  }
  if {$Autoselect eq {}} return
  set myIndex [lsearch -nocase -glob [[::ttk::combobox::LBMaster $w] cget -values] $Autoselect*]
  if {$myIndex < 0} return
  $w selection clear 0 end
  $w activate $myIndex
  $w selection set $myIndex
  $w see $myIndex
}
# Change original procedure to support autocompletion
proc ttk::combobox::LBCancel {lb} {
    Unpost [LBMaster $lb]
set ::ttk::combobox::Autoselect {};#RZ
}

Questions and Suggestions concerning ttk::combobox edit

RLH It would be nice if a widget is involved to see a graphic showing the widget. Not necessary...but nice.

D. McC 2008 Dec 8: OK, after rummaging through the ttk::style man page and trying things out in vain, I give up. Can somebody tell me how to specify the background color for the entry portion of the ttk::combobox? And can somebody tell me why there is not even an option to specify colors of Ttk widgets in the same ultra-simple way as for Tk widgets, e.g., "-bg AntiqueWhite"?

Bryan Oakley 2008 Dec 8: To solve your immediate problem, try this:
 ttk::combobox .cb -style mycombobox.TCombobox
 ttk::style configure mycombobox.TCombobox -fieldbackground bisque

(using "ttk::style map" may be a better choice, but I'll leave that as an exercise for the reader)

As to why there is no option, that's the design philosophy of the themed widgets -- you lose some amount of control over individual widgets but gain the ability to create unified themes.

MSH This no longer works in 8.6 (tried 8.6.1 8.6.4 8.6.5) the only option which changes is -foreground.

D. McC 2008 Dec 9: Thanks--it works! Now I'll see about incorporating that into my color-scheme files.

What I still don't understand is why the programmer isn't given a choice about how much control over individual widgets (and ease of configuring them) to trade off for how much ability to create unified themes.

TLT 2009-11-28 - I was annoyed that the ttk::combobox does not change the cursor to an ibeam when it is inside the text entry widget. The following binding fixes that:
 bind TCombobox <Motion> {
     if {[%W cget -state] eq "normal" && [%W identify %x %y] eq "textarea"} {
         %W configure -cursor xterm
     } else {
         %W configure -cursor ""
     }
 }
 pack [ttk::combobox .cb]

MHo: In the read-only-editfield, how is it possible, e.g. to get the entry Seven? Pressing S always leads to Six (prior in the list), pressing S again does not help, pressing E right after S leads to Eight. This is true for the listbox, too.

jnc: Feb 24, 2010: In my misc-tcl code project, there is updated combo box code. I have not updated it here yet as I don't want to make daily updates here. The code on the misc-tcl project page allows properly for the Up/Down use of arrow keys to select items when in the readonly edit field. So, to get to Seven, you would press S and then use your up/down arrow key to navigate to Seven. This is how Windows works. I would actually prefer it to allow allow typing of SE which would go to Seven, but this would be non-standard. I am sure you can modify the above code for that type of action if you so desired.

MHo: At least within list boxes/tables (like explorer windows) windows navigates to the next matching entry which each keypress. So, the first S would go to Seven, the next S to Six etc.

My miscellaneous Tcl code is located at: http://jeremy.cowgar.com/misctcl/index.cgi/index and the combobox code is specifically located at: http://jeremy.cowgar.com/misctcl/index.cgi/doc/tip/combobox/combobox.tcl .. That will always be my latest source. The source (as of Feb 24, 2010) has been submitted to Tcl/Tk as the default behavior. No action has been taken on it as of this time.

LV 2010-06-09

In the iwidgets combobox, one had the ability to specified a command to execute when one of the menu items in the dropdown list is selected. How does one do that with the ttk version of the combobox?

hae 2010-06-09

The ttk::combobox does not have this. However here is a basic example to have a callback, when an item is selected.
package require tk
package require Tk
package require Ttk
set values [list Orange Apple Peas]
set c [ttk::combobox .cbx -values $values]
pack $c

proc OnComboSelected { w } {
    puts [info level 0]
}

bind $c <<ComboboxSelected>> [list OnComboSelected %W]

Okay, so I attempted to use the above code. However, I do not get the item selected displayed when I click on an entry. Instead, I get the text: "OnComboSelected .cbx" output.

So, when I change OnComboSelected to read
proc OnComboSelected { w } {
        puts [$w get]
}

I get the selected item output.

What a pain for people trying to use ttk from iwidgets!

[Leon] - 2010-12-09 15:53:53

Salute!Need help! How change size of pop-down items that we have on list? Just need to refer to this list.But how?? Thank you in advance!

HaO: There is new info in the font and color box below. Could you check it out. Does it help for you? For me, the question is not clear. Size means x-y size ? Or font size ?

  Change fonts

HaO 2011-04-20 Change the entry font for one Combobox:
font create EntryFont -size 20
ttk::combobox .b -font EntryFont

and for all comboboxes:
option add *TCombobox.font EntryFont

Change the font size for all combobox dropdown listboxes:
option add *TCombobox*Listbox.font EntryFont

(from the file tcl8.5/lib/tklib/ttk/combobox.tcl)

Why is there no -font option

HaO 2015-09-18: I try to answer to the tk ticket [2]:
ttk::style -font does not work for TCombobox, TEntry or TSpinbox on either LinuxMint 17.2 or Windows 7.
ttk::style -font does work for the other ttk widgets.

package require Tk

font create x
font configure x -size 36
ttk::style configure TCombobox -font x
ttk::combobox .c -values [list abc def ghi jkl]
pack .c -in .

The ttk::combobox is composed of sub-widgets where each has an own style.

Lets explore the structure (Windows):
% winfo class .c
TCombobox

% ttk::style layout TCombobox
Combobox.border -sticky nswe -children {Combobox.rightdownarrow -side right -sticky ns Combobox.padding -expand 1 -sticky nswe -children {Combobox.focus -expand 1 -sticky nswe -children {Combobox.textarea -sticky nswe}}}

% ttk::style element options TCombobox.textarea
-font -width

So the text area has its own -font option. Thats why the upper approach does not style the dropdown box.

But I can not find the font for the entry box here.

Set the font of the dropdown box

On the clt thread "changing default font in TCombobox" on 2015-09-21 [3], Brad Lanam gave the following recipe:
.combo configure -font myfont   ; # the entry font
set popdown [ttk::combobox::PopdownWindow .combo]
$popdown.f.l configure -font myfont ; # the font for the dropdown listbox 

  Disabled/Readonly color (and pointer to color change)

Intesting thread 'Propose new layout for ttk::combobox and ttk::spinbox' on clt on 2011-12-04.

Enhanced combobox/spinbox layout whith an answer by Pat Thoyts about fixed readonly/disabled colors and a link to a test program: [4]

2013-04-15 HaO: Another interesting thread on clt:

Question: I am trying to change the ttk::combobox background on linux to white when the widget state is readonly?

Answer by Koen Danckaert:
ttk::style map TCombobox -fieldbackground {readonly white disabled #d9d9d9} 

The wiki page Changing Widget Colors shows how to change all colors of the widget. In addition, it gives additional insight to the structure.

AMG: How do I change the disabled color when using the vista theme? There is no -fieldbackground style map. It's just white all the time, which is really confusing since it's same color when enabled and it's different from the other widgets which do gray out when disabled.

bll 2018-7-31: Found an example of what windows does: Right-click on a disk drive/Properties/Quota tab/Show Quota Settings. Windows' drop-drop list has a gradient, and that goes dimmer on disable, so it appears a bit grey. They also remove the text display.

Tk's combobox doesn't change the fieldbackground, doesn't remove the text display, and the rest goes grey. Tk's entry widget does change the fieldbackground (though the color can't be changed), so it should be possible by changing the source code.

Try this:

vistaTheme.tcl
         # Combobox
        ttk::style configure TCombobox -padding 2
+        ttk::style element create Combobox.background vsapi \
+            EDIT 3 {disabled 3 {} 0}
         ttk::style element create Combobox.field vsapi \
             COMBOBOX 2 {{} 1}
         ttk::style element create Combobox.border vsapi \
@@ -65,12 +67,14 @@
             -syssize {SM_CXVSCROLL SM_CYVSCROLL}
         ttk::style layout TCombobox {
             Combobox.border -sticky nswe -border 0 -children {
-                Combobox.rightdownarrow -side right -sticky ns
+               Combobox.background  -sticky nswe -children {
                 Combobox.padding -expand 1 -sticky nswe -children {
                     Combobox.focus -expand 1 -sticky nswe -children {
                         Combobox.textarea -sticky nswe
                     }
                 }
+                  Combobox.rightdownarrow -side right -sticky ns
+                }
             }
         }
         # Vista.Combobox droplist frame

  How to change a tk::combobox width to display the longest tk::combobox entry for easy reading?

Let's say you have a column of destinations you already have inside a table called item_in_out stored in some database called warehouse . You are supposed to record the destination of every item whenever and item is pulled out from a warehouse or store. So, as you record destinations, you don't want to repeat typing them. So we depend on the combobox autocompletion proc ComboBoxAutoComplete which is written on the top of this wiki page PLUS the database distinct listing of previously recorded destinations. To display the destinations list in a combobox and make it obvious and clear and readable, we'll have to set the destinations list combobox width to the longest string length of all destinations.

Here I am going to show you what works and what does not work. I am going to use tdbc::mysql for database connectivity.

The following proc gets distinct destinations and it returns them in a tcl list variable.
package require tdbc::mysql

#dbcon is the mysql connection command.
tdbc::mysql::connection create dbcon -database warehouse -user root  -password myp@ssw0d -host localhost

proc destinations { path } {
 
  #$path is the combobox widget path that you want fix its width

   set query_all_destinations "select distinct destination from item_in_out"
   set statement [dbcon prepare $query_all_destinations]
   set destinations_list [list]
   set max_destination_strlength 0
   
  $statement foreach row {
      
      #the two lines below finds the longest string length amongst all destinations
      set single_destination [dict get $row destination ]
      if { [string length $single_destination] > $max_destination_strlength } { set max_destination_strlength [string length $single_destination] }
     
     lappend destinations_list $single_destination
   }
 
  #here we set the width according to the longest length found.
  $path configure -width $max_destination_strlength

 return $destinations_list
}

You might think that this way of calling the combobox is correct , then you're wrong. I say so because this can fool you because of tcl programming habits. here the combo is actually not defined or created yet.
ttk::combobox .destinations_combo -values [ destinations .destinations_combo ]
bind  .destinations_combo  <KeyRelease> [list ComboBoxAutoComplete  .destinations_combo %K]

The correct way is this. The reason is that the the combobox must be defined first, then you can do whatever you want.
ttk::combobox  .destinations_combo  
.destinations_combo  configure -values [ destinations .item_io_labelframe.destination_text ]
bind   .destinations_combo  <KeyRelease> [list ComboBoxAutoComplete  .destinations_combo  %K ]

Please remember that after you insert a new record in the table item_in_out you'll have to re-update the destinations combobox just in case you have inserted a new destination. Use this line of code to do re-update.
.destinations_combo  configure -values [ destinations .destinations_combo  ]

See also: ComboBox megawidget with adjusted width