# Tix.py -- Tix widget wrappers.
# For Tix, see http://tix.sourceforge.net
# - Sudhir Shenoy (sshenoy@gol.com), Dec. 1995.
# based on an idea of Jean-Marc Lugrin (lugrin@ms.com)
# NOTE: In order to minimize changes to Tkinter.py, some of the code here
# (TixWidget.__init__) has been taken from Tkinter (Widget.__init__)
# and will break if there are major changes in Tkinter.
# The Tix widgets are represented by a class hierarchy in python with proper
# inheritance of base classes.
# As a result after creating a 'w = StdButtonBox', I can write
# w.ok['text'] = 'Who Cares'
# or w.ok['bg'] = w['bg']
# Compare the demo tixwidgets.py to the original Tcl program and you will
# appreciate the advantages.
from tkinter import _cnfmerge
import _tkinter # If this fails your Python may not be configured for Tk
# Some more constants (for consistency with Tkinter)
# A few useful constants for the Grid widget
DECREASING = 'decreasing'
INCREASING = 'increasing'
# Some constants used by Tkinter dooneevent()
TCL_WINDOW_EVENTS = 1 << 2
TCL_TIMER_EVENTS = 1 << 4
# BEWARE - this is implemented by copying some code from the Widget class
# in Tkinter (to override Widget initialization) and is therefore
# Could probably add this to Tkinter.Misc
"""The tix commands provide access to miscellaneous elements
of Tix's internal state and the Tix application context.
Most of the information manipulated by these commands pertains
to the application as a whole, or to a screen or
display, rather than to a particular window.
This is a mixin class, assumed to be mixed to Tkinter.Tk
that supports the self.tk.call method.
def tix_addbitmapdir(self, directory):
"""Tix maintains a list of directories under which
the tix_getimage and tix_getbitmap commands will
search for image files. The standard bitmap directory
is $TIX_LIBRARY/bitmaps. The addbitmapdir command
adds directory into this list. By using this
command, the image files of an applications can
also be located using the tix_getimage or tix_getbitmap
return self.tk.call('tix', 'addbitmapdir', directory)
def tix_cget(self, option):
"""Returns the current value of the configuration
option given by option. Option may be any of the
options described in the CONFIGURATION OPTIONS section.
return self.tk.call('tix', 'cget', option)
def tix_configure(self, cnf=None, **kw):
"""Query or modify the configuration options of the Tix application
context. If no option is specified, returns a dictionary all of the
available options. If option is specified with no value, then the
command returns a list describing the one named option (this list
will be identical to the corresponding sublist of the value
returned if no option is specified). If one or more option-value
pairs are specified, then the command modifies the given option(s)
to have the given value(s); in this case the command returns an
empty string. Option may be any of the configuration options.
cnf = _cnfmerge((cnf, kw))
return self._getconfigure('tix', 'configure')
return self._getconfigure1('tix', 'configure', '-'+cnf)
return self.tk.call(('tix', 'configure') + self._options(cnf))
def tix_filedialog(self, dlgclass=None):
"""Returns the file selection dialog that may be shared among
different calls from this application. This command will create a
file selection dialog widget when it is called the first time. This
dialog will be returned by all subsequent calls to tix_filedialog.
An optional dlgclass parameter can be passed to specified what type
of file selection dialog widget is desired. Possible options are
tix FileSelectDialog or tixExFileSelectDialog.
return self.tk.call('tix', 'filedialog', dlgclass)
return self.tk.call('tix', 'filedialog')
def tix_getbitmap(self, name):
"""Locates a bitmap file of the name name.xpm or name in one of the
bitmap directories (see the tix_addbitmapdir command above). By
using tix_getbitmap, you can avoid hard coding the pathnames of the
bitmap files in your application. When successful, it returns the
complete pathname of the bitmap file, prefixed with the character
'@'. The returned value can be used to configure the -bitmap
option of the TK and Tix widgets.
return self.tk.call('tix', 'getbitmap', name)
def tix_getimage(self, name):
"""Locates an image file of the name name.xpm, name.xbm or name.ppm
in one of the bitmap directories (see the addbitmapdir command
above). If more than one file with the same name (but different
extensions) exist, then the image type is chosen according to the
depth of the X display: xbm images are chosen on monochrome
displays and color images are chosen on color displays. By using
tix_ getimage, you can avoid hard coding the pathnames of the
image files in your application. When successful, this command
returns the name of the newly created image, which can be used to
configure the -image option of the Tk and Tix widgets.
return self.tk.call('tix', 'getimage', name)
def tix_option_get(self, name):
"""Gets the options maintained by the Tix
scheme mechanism. Available options include:
bold_font dark1_bg dark1_fg
dark2_bg dark2_fg disabled_fg
inactive_bg inactive_fg input1_bg
input2_bg italic_font light1_bg
light1_fg light2_bg light2_fg
menu_font output1_bg output2_bg
select_bg select_fg selector
# could use self.tk.globalgetvar('tixOption', name)
return self.tk.call('tix', 'option', 'get', name)
def tix_resetoptions(self, newScheme, newFontSet, newScmPrio=None):
"""Resets the scheme and fontset of the Tix application to
newScheme and newFontSet, respectively. This affects only those
widgets created after this call. Therefore, it is best to call the
resetoptions command before the creation of any widgets in a Tix
The optional parameter newScmPrio can be given to reset the
priority level of the Tk options set by the Tix schemes.
Because of the way Tk handles the X option database, after Tix has
been has imported and inited, it is not possible to reset the color
schemes and font sets using the tix config command. Instead, the
tix_resetoptions command must be used.
if newScmPrio is not None:
return self.tk.call('tix', 'resetoptions', newScheme, newFontSet, newScmPrio)
return self.tk.call('tix', 'resetoptions', newScheme, newFontSet)
class Tk(tkinter.Tk, tixCommand):
"""Toplevel widget of Tix which represents mostly the main window
of an application. It has an associated Tcl interpreter."""
def __init__(self, screenName=None, baseName=None, className='Tix'):
tkinter.Tk.__init__(self, screenName, baseName, className)
tixlib = os.environ.get('TIX_LIBRARY')
self.tk.eval('global auto_path; lappend auto_path [file dir [info nameof]]')
self.tk.eval('global auto_path; lappend auto_path {%s}' % tixlib)
self.tk.eval('global tcl_pkgPath; lappend tcl_pkgPath {%s}' % tixlib)
# Load Tix - this should work dynamically or statically
# If it's static, tcl/tix8.1/pkgIndex.tcl should have
# If it's dynamic under Unix, tcl/tix8.1/pkgIndex.tcl should have
# 'load libtix8.1.8.3.so Tix'
self.tk.eval('package require Tix')
# For safety, remove the delete_window binding before destroy
self.protocol("WM_DELETE_WINDOW", "")
# The Tix 'tixForm' geometry manager
"""The Tix Form geometry manager
Widgets can be arranged by specifying attachments to other widgets.
See Tix documentation for complete details"""
def config(self, cnf={}, **kw):
self.tk.call('tixForm', self._w, *self._options(cnf, kw))
def __setitem__(self, key, value):
Form.form(self, {key: value})
return self.tk.call('tixForm', 'check', self._w)
self.tk.call('tixForm', 'forget', self._w)
def grid(self, xsize=0, ysize=0):
if (not xsize) and (not ysize):
x = self.tk.call('tixForm', 'grid', self._w)
z = z + (self.tk.getint(x),)
return self.tk.call('tixForm', 'grid', self._w, xsize, ysize)
def info(self, option=None):
return self.tk.call('tixForm', 'info', self._w)
return self.tk.call('tixForm', 'info', self._w, option)
return [self._nametowidget(x) for x in
'tixForm', 'slaves', self._w))]
tkinter.Widget.__bases__ = tkinter.Widget.__bases__ + (Form,)
class TixWidget(tkinter.Widget):
"""A TixWidget class is used to package all (or most) Tix widgets.
Widget initialization is extended in two ways:
1) It is possible to give a list of options which must be part of
the creation command (so called Tix 'static' options). These cannot be
given as a 'config' command later.
2) It is possible to give the name of an existing TK widget. These are
child widgets created automatically by a Tix mega-widget. The Tk call
to create these widgets is therefore bypassed in TixWidget.__init__
Both options are for use by subclasses only.
def __init__ (self, master=None, widgetName=None,
static_options=None, cnf={}, kw={}):
# Merge keywords and dictionary arguments
cnf = _cnfmerge((cnf, kw))
# Move static options into extra. static_options must be
# a list of keywords (or None).
# 'options' is always a static option
static_options.append('options')
static_options = ['options']
for k,v in list(cnf.items()):
extra = extra + ('-' + k, v)
self.widgetName = widgetName
Widget._setup(self, master, cnf)
# If widgetName is None, this is a dummy creation call where the
# corresponding Tk widget has already been created by Tix
self.tk.call(widgetName, self._w, *extra)
# Non-static options - to be done via a 'config' command
# Dictionary to hold subwidget names for easier access. We can't
# use the children list because the public Tix names may not be the
# same as the pathname component
# We set up an attribute access function so that it is possible to
# do w.ok['text'] = 'Hello' rather than w.subwidget('ok')['text'] = 'Hello'
# when w is a StdButtonBox.
# We can even do w.ok.invoke() because w.ok is subclassed from the
# Button class if you go through the proper constructors
def __getattr__(self, name):
if name in self.subwidget_list:
return self.subwidget_list[name]
raise AttributeError(name)
def set_silent(self, value):
"""Set a variable without calling its action routine"""
self.tk.call('tixSetSilent', self._w, value)
def subwidget(self, name):
"""Return the named subwidget (which must have been created by
n = self._subwidget_name(name)
raise TclError("Subwidget " + name + " not child of " + self._name)
# Remove header of name and leading dot
return self._nametowidget(n)
def subwidgets_all(self):
"""Return all subwidgets."""
names = self._subwidget_names()
name = name[len(self._w)+1:]
retlist.append(self._nametowidget(name))
# some of the widgets are unknown e.g. border in LabelFrame
def _subwidget_name(self,name):
"""Get a subwidget name (returns a String, not a Widget !)"""
return self.tk.call(self._w, 'subwidget', name)
def _subwidget_names(self):
"""Return the name of all subwidgets."""
x = self.tk.call(self._w, 'subwidgets', '-all')
return self.tk.splitlist(x)
def config_all(self, option, value):
"""Set configuration options for all subwidgets (and self)."""
elif not isinstance(option, str):
if not isinstance(value, str):
names = self._subwidget_names()
self.tk.call(name, 'configure', '-' + option, value)
# These are missing from Tkinter
def image_create(self, imgtype, cnf={}, master=None, **kw):
if kw and cnf: cnf = _cnfmerge((cnf, kw))
options = options + ('-'+k, v)
return master.tk.call(('image', 'create', imgtype,) + options)
def image_delete(self, imgname):
self.tk.call('image', 'delete', imgname)
# May happen if the root was destroyed
# Subwidgets are child widgets created automatically by mega-widgets.
# In python, we have to create these subwidgets manually to mirror their
class TixSubWidget(TixWidget):
This is used to mirror child widgets automatically created
by Tix/Tk as part of a mega-widget in Python (which is not informed
def __init__(self, master, name,
destroy_physically=1, check_intermediate=1):
path = master._subwidget_name(name)
path = path[len(master._w)+1:]
if not check_intermediate:
TixWidget.__init__(self, master, None, None, {'name' : name})
# Ensure that the intermediate widgets exist
for i in range(len(plist) - 1):
n = '.'.join(plist[:i+1])
w = master._nametowidget(n)
# Create the intermediate widget
parent = TixSubWidget(parent, plist[i],
# The Tk widget name is in plist, not in name
TixWidget.__init__(self, parent, None, None, {'name' : name})
self.destroy_physically = destroy_physically
# For some widgets e.g., a NoteBook, when we call destructors,
# we must be careful not to destroy the frame widget since this
# also destroys the parent NoteBook thus leading to an exception
# in Tkinter when it finally calls Tcl to destroy the NoteBook
for c in list(self.children.values()): c.destroy()
if self._name in self.master.children:
del self.master.children[self._name]
if self._name in self.master.subwidget_list:
del self.master.subwidget_list[self._name]
if self.destroy_physically:
# This is bypassed only for a few widgets
self.tk.call('destroy', self._w)
# Useful class to create a display style - later shared by many items.
# Contributed by Steffen Kremser
"""DisplayStyle - handle configuration options shared by
(multiple) Display Items"""
def __init__(self, itemtype, cnf={}, *, master=None, **kw):
master = cnf['refwindow']
master = tkinter._get_default_root('create display style')
self.stylename = self.tk.call('tixDisplayStyle', itemtype,
def _options(self, cnf, kw):
cnf = _cnfmerge((cnf, kw))
self.tk.call(self.stylename, 'delete')
def __setitem__(self,key,value):
self.tk.call(self.stylename, 'configure', '-%s'%key, value)
def config(self, cnf={}, **kw):