After digging through combobox.tcl
source code I've come up with the following subclass of ttk.Combobox
. JustifiedCombobox
justifies the pop-down list's items almost precisely after1 pop-down list's been first created & customized and then displayed. After the pop-down list's been created, setting self.justify
value to a valid one will again, customize the justification almost right after the pop-down list's first been displayed. Enjoy:
try: # In order to be able to import tkinter for
import tkinter as tk # either in python 2 or in python 3
from tkinter import ttk
except:
import Tkinter as tk
import ttk
class JustifiedCombobox(ttk.Combobox):
"""
Creates a ttk.Combobox widget with its drop-down list items
justified with self.justify as late as possible.
"""
def __init__(self, master, *args, **kwargs):
ttk.Combobox.__init__(self, master, *args, **kwargs)
self.justify = 'center'
def _justify_popdown_list_text(self):
self._initial_bindtags = self.bindtags()
_bindtags = list(self._initial_bindtags)
_index_of_class_tag = _bindtags.index(self.winfo_class())
# This dummy tag needs to be unique per object, and also needs
# to be not equal to str(object)
self._dummy_tag = '_' + str(self)
_bindtags.insert(_index_of_class_tag + 1, self._dummy_tag)
self.bindtags(tuple(_bindtags))
_events_that_produce_popdown = tuple([ '<KeyPress-Down>',
'<ButtonPress-1>',
'<Shift-ButtonPress-1>',
'<Double-ButtonPress-1>',
'<Triple-ButtonPress-1>',
])
for _event_name in _events_that_produce_popdown:
self.bind_class(self._dummy_tag, _event_name,
self._initial_event_handle)
def _initial_event_handle(self, event):
_instate = str(self['state'])
if _instate != 'disabled':
if event.keysym == 'Down':
self._justify()
else:
_ = self.tk.eval('{} identify element {} {}'.format(self,
event.x, event.y))
__ = self.tk.eval('string match *textarea {}'.format(_))
_is_click_in_entry = bool(int(__))
if (_instate == 'readonly') or (not _is_click_in_entry):
self._justify()
def _justify(self):
self.tk.eval('{}.popdown.f.l configure -justify {}'.format(self,
self.justify))
self.bindtags(self._initial_bindtags)
def __setattr__(self, name, value):
self.__dict__[name] = value
if name == 'justify':
self._justify_popdown_list_text()
def select_handle():
global a
_selected = a['values'][a.current()]
if _selected in ("left", "center", "right"):
a.justify = _selected
if __name__ == '__main__':
root = tk.Tk()
for s in ('normal', 'readonly', 'disabled'):
JustifiedCombobox(root, state=s, values=[1, 2, 3]).grid()
a = JustifiedCombobox(root, values=["Justify me!", "left", "center", "right"])
a.current(0)
a.grid()
a.bind("<<ComboboxSelected>>", lambda event: select_handle())
root.mainloop()
1 It basically makes use of bindtag event queue. This was mostly possible thanks to being able to creating a custom bindtag.