1 # Copyright (c) 2008, Guilherme Polo
   2 # All rights reserved.
   3 #
   4 # Redistribution and use in source and binary forms, with or without
   5 # modification, are permitted provided that the following conditions are met:
   6 #
   7 #  * Redistributions of source code must retain the above copyright notice,
   8 #    this list of conditions and the following disclaimer.
   9 #  * Redistributions in binary form must reproduce the above copyright notice,
  10 #    this list of conditions and the following disclaimer in the documentation
  11 #    and/or other materials provided with the distribution.
  12 #
  13 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  14 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  16 # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  17 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  18 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  19 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  20 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  21 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  22 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  23 # POSSIBILITY OF SUCH DAMAGE.
  24 
  25 """
  26 This contains a wrapper class for the tktable widget as well a class for using
  27 tcl arrays that are, in some instances, required by tktable.
  28 """
  29 
  30 __author__ = "Guilherme Polo <ggpolo@gmail.com>"
  31 
  32 __all__ = ["ArrayVar", "Table"]
  33 
  34 import os
  35 import Tkinter
  36 
  37 def _setup_master(master):
  38     if master is None:
  39         if Tkinter._support_default_root:
  40             master = Tkinter._default_root or Tkinter.Tk()
  41         else:
  42             raise RuntimeError("No master specified and Tkinter is "
  43                 "configured to not support default master")
  44     return master
  45 
  46 class ArrayVar(Tkinter.Variable):
  47     """Class for handling Tcl arrays.
  48 
  49     An array is actually an associative array in Tcl, so this class supports
  50     some dict operations.
  51     """
  52 
  53     def __init__(self, master=None, name=None):
  54         # Tkinter.Variable.__init__ is not called on purpose! I don't wanna
  55         # see an ugly _default value in the pretty array.
  56         self._master = _setup_master(master)
  57         self._tk = self._master.tk
  58         if name:
  59             self._name = name
  60         else:
  61             self._name = 'PY_VAR%s' % id(self)
  62 
  63     def __del__(self):
  64         if bool(self._tk.call('info', 'exists', self._name)):
  65             self._tk.globalunsetvar(self._name)
  66 
  67     def __len__(self):
  68         return int(self._tk.call('array', 'size', str(self)))
  69 
  70     def __getitem__(self, key):
  71         return self.get(key)
  72 
  73     def __setitem__(self, key, value):
  74         self.set(**{str(key): value})
  75 
  76     def names(self):
  77         return self._tk.call('array', 'names', self._name)
  78 
  79     def get(self, key=None):
  80         if key is None:
  81             flatten_pairs = self._tk.call('array', 'get', str(self))
  82             return dict(zip(flatten_pairs[::2], flatten_pairs[1::2]))
  83 
  84         return self._tk.globalgetvar(str(self), str(key))
  85 
  86     def set(self, **kw):
  87         self._tk.call('array', 'set', str(self), Tkinter._flatten(kw.items()))
  88 
  89     def unset(self, pattern=None):
  90         """Unsets all of the elements in the array. If pattern is given, only
  91         the elements that match pattern are unset. """
  92         self._tk.call('array', 'unset', str(self), pattern)
  93 
  94 
  95 _TKTABLE_LOADED = False
  96 
  97 class Table(Tkinter.Widget):
  98     """Create and manipulate tables."""
  99 
 100     _switches = ('holddimensions', 'holdselection', 'holdtags', 'holdwindows',
 101                  'keeptitles', '-')
 102     _tabsubst_format = ('%c', '%C', '%i', '%r', '%s', '%S', '%W')
 103     _tabsubst_commands = ('browsecommand', 'browsecmd', 'command',
 104                           'selectioncommand', 'selcmd',
 105                           'validatecommand', 'valcmd')
 106 
 107     def __init__(self, master=None, **kw):
 108         master = _setup_master(master)
 109         global _TKTABLE_LOADED
 110         if not _TKTABLE_LOADED:
 111             tktable_lib = os.environ.get('TKTABLE_LIBRARY')
 112             if tktable_lib:
 113                 master.tk.eval('global auto_path; '
 114                                 'lappend auto_path {%s}' % tktable_lib)
 115             master.tk.call('package', 'require', 'Tktable')
 116             _TKTABLE_LOADED = True
 117 
 118         Tkinter.Widget.__init__(self, master, 'table', kw)
 119 
 120 
 121     def _options(self, cnf, kw=None):
 122         if kw:
 123             cnf = Tkinter._cnfmerge((cnf, kw))
 124         else:
 125             cnf = Tkinter._cnfmerge(cnf)
 126 
 127         res = ()
 128         for k, v in cnf.iteritems():
 129             if callable(v):
 130                 if k in self._tabsubst_commands:
 131                     v = "%s %s"  % (self._register(v, self._tabsubst),
 132                                     ' '.join(self._tabsubst_format))
 133                 else:
 134                     v = self._register(v)
 135             res += ('-%s' % k, v)
 136 
 137         return res
 138 
 139 
 140     def _tabsubst(self, *args):
 141         if len(args) != len(self._tabsubst_format):
 142             return args
 143 
 144         tk = self.tk
 145         c, C, i, r, s, S, W = args
 146         e = Tkinter.Event()
 147 
 148         e.widget = self
 149         e.c = tk.getint(c)
 150         e.i = tk.getint(i)
 151         e.r = tk.getint(r)
 152         e.C = "%d,%d" % (e.r, e.c)
 153         e.s = s
 154         e.S = S
 155         try:
 156             e.W = self._nametowidget(W)
 157         except KeyError:
 158             e.W = None
 159 
 160         return (e,)
 161 
 162 
 163     def _handle_switches(self, args):
 164         args = args or ()
 165         return tuple(('-%s' % x) for x in args if x in self._switches)
 166 
 167 
 168     def activate(self, index):
 169         """Set the active cell to the one indicated by index."""
 170         self.tk.call(self._w, 'activate', index)
 171 
 172 
 173     def bbox(self, first, last=None):
 174         """Return the bounding box for the specified cell (range) as a
 175         4-tuple of x, y, width and height in pixels. It clips the box to
 176         the visible portion, if any, otherwise an empty tuple is returned."""
 177         return self._getints(self.tk.call(self._w, 'bbox', first, last)) or ()
 178 
 179 
 180     def clear(self, option, first=None, last=None):
 181         """This is a convenience routine to clear certain state information
 182         managed by the table. first and last represent valid table indices.
 183         If neither are specified, then the command operates on the whole
 184         table."""
 185         self.tk.call(self._w, 'clear', option, first, last)
 186 
 187 
 188     def clear_cache(self, first=None, last=None):
 189         """Clear the specified section of the cache, if the table has been
 190         keeping one."""
 191         self.clear('cache', first, last)
 192 
 193 
 194     def clear_sizes(self, first=None, last=None):
 195         """Clear the specified row and column areas of specific height/width
 196         dimensions. When just one index is specified, for example 2,0, that
 197         is interpreted as row 2 and column 0."""
 198         self.clear('sizes', first, last)
 199 
 200 
 201     def clear_tags(self, first=None, last=None):
 202         """Clear the specified area of tags (all row, column and cell tags)."""
 203         self.clear('tags', first, last)
 204 
 205 
 206     def clear_all(self, first=None, last=None):
 207         """Perform all of the above clear functions on the specified area."""
 208         self.clear('all', first, last)
 209 
 210 
 211     def curselection(self, value=None):
 212         """With no arguments, it returns the sorted indices of the currently
 213         selected cells. Otherwise it sets all the selected cells to the given
 214         value if there is an associated ArrayVar and the state is not
 215         disabled."""
 216         result = self.tk.call(self._w, 'curselection', value)
 217         if value is None:
 218             return result
 219 
 220 
 221     def curvalue(self, value=None):
 222         """If no value is given, the value of the cell being edited (indexed
 223         by active) is returned, else it is set to the given value. """
 224         return self.tk.call(self._w, 'curvalue', value)
 225 
 226 
 227     def delete_active(self, index1, index2=None):
 228         """Deletes text from the active cell. If only one index is given,
 229         it deletes the character after that index, otherwise it deletes from
 230         the first index to the second. index can be a number, insert or end."""
 231         self.tk.call(self._w, 'delete', 'active', index1, index2)
 232 
 233 
 234     def delete_cols(self, index, count=None, switches=None):
 235         args = self._handle_switches(switches) + (index, count)
 236         self.tk.call(self._w, 'delete', 'cols', *args)
 237 
 238 
 239     def delete_rows(self, index, count=None, switches=None):
 240         args = self._handle_switches(switches) + (index, count)
 241         self.tk.call(self._w, 'delete', 'rows', *args)
 242 
 243 
 244     def get(self, first, last=None):
 245         """Returns the value of the cells specified by the table indices
 246         first and (optionally) last."""
 247         return self.tk.call(self._w, 'get', first, last)
 248 
 249 
 250     def height(self, row=None, **kwargs):
 251         """If row and kwargs are not given, a list describing all rows for
 252         which a width has been set is returned.
 253         If row is given, the height of that row is returnd.
 254         If kwargs is given, then it sets the key/value pairs, where key is a
 255         row and value represents the height for the row."""
 256         if row is None and not kwargs:
 257             pairs = self.tk.splitlist(self.tk.call(self._w, 'height'))
 258             return dict(pair.split() for pair in pairs)
 259         elif row:
 260             return int(self.tk.call(self._w, 'height', str(row)))
 261 
 262         args = Tkinter._flatten(kwargs.items())
 263         self.tk.call(self._w, 'height', *args)
 264 
 265 
 266     def hidden(self, *args):
 267         """When called without args, it returns all the hidden cells (those
 268         cells covered by a spanning cell). If one index is specified, it
 269         returns the spanning cell covering that index, if any. If multiple
 270         indices are specified, it returns 1 if all indices are hidden cells,
 271         0 otherwise."""
 272         return self.tk.call(self._w, 'hidden', *args)
 273 
 274 
 275     def icursor(self, arg=None):
 276         """If arg is not specified, return the location of the insertion
 277         cursor in the active cell. Otherwise, set the cursor to that point in
 278         the string.
 279 
 280         0 is before the first character, you can also use insert or end for
 281         the current insertion point or the end of the text. If there is no
 282         active cell, or the cell or table is disabled, this will return -1."""
 283         return self.tk.call(self._w, 'icursor', arg)
 284 
 285 
 286     def index(self, index, rc=None):
 287         """Return the integer cell coordinate that corresponds to index in the
 288         form row, col. If rc is specified, it must be either 'row' or 'col' so
 289         only the row or column index is returned."""
 290         res = self.tk.call(self._w, 'index', index, rc)
 291         if rc is None:
 292             return res
 293         else:
 294             return int(res)
 295 
 296 
 297     def insert_active(self, index, value):
 298         """The value is a text string which is inserted at the index postion
 299         of the active cell. The cursor is then positioned after the new text.
 300         index can be a number, insert or end. """
 301         self.tk.call(self._w, 'insert', 'active', index, value)
 302 
 303 
 304     def insert_cols(self, index, count=None, switches=None):
 305         args = self._handle_switches(switches) + (index, count)
 306         self.tk.call(self._w, 'insert', 'cols', *args)
 307 
 308 
 309     def insert_rows(self, index, count=None, switches=None):
 310         args = self._handle_switches(switches) + (index, count)
 311         self.tk.call(self._w, 'insert', 'rows', *args)
 312 
 313 
 314     #def postscript(self, **kwargs):
 315     #    """Skip this command if you are under Windows.
 316     #
 317     #    Accepted options:
 318     #        colormap, colormode, file, channel, first, fontmap, height,
 319     #        last, pageanchor, pageheight, pagewidth, pagex, pagey, rotate,
 320     #        width, x, y
 321     #    """
 322     #    args = ()
 323     #    for key, val in kwargs.iteritems():
 324     #        args += ('-%s' % key, val)
 325     #
 326     #    return self.tk.call(self._w, 'postscript', *args)
 327 
 328 
 329     def reread(self):
 330         """Rereads the old contents of the cell back into the editing buffer.
 331         Useful for a key binding when <Escape> is pressed to abort the edit
 332         (a default binding)."""
 333         self.tk.call(self._w, 'reread')
 334 
 335 
 336     def scan_mark(self, x, y):
 337         self.tk.call(self._w, 'scan', 'mark', x, y)
 338 
 339 
 340     def scan_dragto(self, x, y):
 341         self.tk.call(self._w, 'scan', 'dragto', x, y)
 342 
 343 
 344     def see(self, index):
 345         self.tk.call(self._w, 'see', index)
 346 
 347 
 348     def selection_anchor(self, index):
 349         self.tk.call(self._w, 'selection', 'anchor', index)
 350 
 351 
 352     def selection_clear(self, first, last=None):
 353         self.tk.call(self._w, 'selection', 'clear', first, last)
 354 
 355 
 356     def selection_includes(self, index):
 357         return self.getboolean(self.tk.call(self._w, 'selection', 'includes',
 358                                             index))
 359 
 360 
 361     def selection_set(self, first, last=None):
 362         self.tk.call(self._w, 'selection', 'set', first, last)
 363 
 364 
 365     def set(self, rc=None, index=None, *args, **kwargs):
 366         """If rc is specified (either 'row' or 'col') then it is assumes that
 367         args (if given) represents values which will be set into the
 368         subsequent columns (if row is specified) or rows (for col).
 369         If index is not None and args is not given, then it will return the
 370         value(s) for the cell(s) specified.
 371 
 372         If kwargs is given, assumes that each key in kwargs is a index in this
 373         table and sets the specified index to the associated value. Table
 374         validation will not be triggered via this method.
 375 
 376         Note that the table must have an associated array (defined through the
 377         variable option) in order to this work."""
 378         if not args and index is not None:
 379             if rc:
 380                 args = (rc, index)
 381             else:
 382                 args = (index, )
 383             return self.tk.call(self._w, 'set', *args)
 384 
 385         if rc is None:
 386             args = Tkinter._flatten(kwargs.items())
 387             self.tk.call(self._w, 'set', *args)
 388         else:
 389             self.tk.call(self._w, 'set', rc, index, args)
 390 
 391 
 392     def spans(self, index=None, **kwargs):
 393         """Manipulate row/col spans.
 394 
 395         When called with no arguments, all known spans are returned as a dict.
 396         When called with only the index, the span for that index only is
 397         returned, if any. Otherwise kwargs is assumed to contain keys/values
 398         pairs used to set spans. A span starts at the row,col defined by a key
 399         and continues for the specified number of rows,cols specified by
 400         its value. A span of 0,0 unsets any span on that cell."""
 401         if kwargs:
 402             args = Tkinter._flatten(kwargs.items())
 403             self.tk.call(self._w, 'spans', *args)
 404         else:
 405             return self.tk.call(self._w, 'spans', index)
 406 
 407 
 408     def tag_cell(self, tagname, *args):
 409         return self.tk.call(self._w, 'tag', 'cell', tagname, *args)
 410 
 411 
 412     def tag_cget(self, tagname, option):
 413         return self.tk.call(self._w, 'tag', 'cget', tagname, '-%s' % option)
 414 
 415 
 416     def tag_col(self, tagname, *args):
 417         return self.tk.call(self._w, 'tag', 'col', tagname, *args)
 418 
 419 
 420     def tag_configure(self, tagname, option=None, **kwargs):
 421         """Query or modify options associated with the tag given by tagname.
 422 
 423         If no option is specified, a dict describing all of the available
 424         options for tagname is returned. If option is specified, then the
 425         command returns a list describing the one named option. Lastly, if
 426         kwargs is given then it corresponds to option-value pairs that should
 427         be modified."""
 428         if option is None and not kwargs:
 429             split1 = self.tk.splitlist(
 430                     self.tk.call(self._w, 'tag', 'configure', tagname))
 431 
 432             result = {}
 433             for item in split1:
 434                 res = self.tk.splitlist(item)
 435                 result[res[0]] = res[1:]
 436 
 437             return result
 438 
 439         elif option:
 440             return self.tk.call(self._w, 'tag', 'configure', tagname,
 441                                 '-%s' % option)
 442 
 443         else:
 444             args = ()
 445             for key, val in kwargs.iteritems():
 446                 args += ('-%s' % key, val)
 447 
 448             self.tk.call(self._w, 'tag', 'configure', tagname, *args)
 449 
 450 
 451     def tag_delete(self, tagname):
 452         self.tk.call(self._w, 'tag', 'delete', tagname)
 453 
 454 
 455     def tag_exists(self, tagname):
 456         return self.getboolean(self.tk.call(self._w, 'tag', 'exists', tagname))
 457 
 458 
 459     def tag_includes(self, tagname, index):
 460         return self.getboolean(self.tk.call(self._w, 'tag', 'includes',
 461                                             tagname, index))
 462 
 463 
 464     def tag_lower(self, tagname, belowthis=None):
 465         self.tk.call(self._w, 'tag', 'lower', belowthis)
 466 
 467 
 468     def tag_names(self, pattern=None):
 469         return self.tk.call(self._w, 'tag', 'names', pattern)
 470 
 471 
 472     def tag_raise(self, tagname, abovethis=None):
 473         self.tk.call(self._w, 'tag', 'raise', tagname, abovethis)
 474 
 475 
 476     def tag_row(self, tagname, *args):
 477         return self.tk.call(self._w, 'tag', 'row', tagname, *args)
 478 
 479 
 480     def validate(self, index):
 481         """Explicitly validates the specified index based on the current
 482         callback set for the validatecommand option. Return 0 or 1 based on
 483         whether the cell was validated."""
 484         return self.tk.call(self._w, 'validate', index)
 485 
 486 
 487     @property
 488     def version(self):
 489         """Return tktable's package version."""
 490         return self.tk.call(self._w, 'version')
 491 
 492 
 493     def width(self, column=None, **kwargs):
 494         """If column and kwargs are not given, a dict describing all columns
 495         for which a width has been set is returned.
 496         If column is given, the width of that column is returnd.
 497         If kwargs is given, then it sets the key/value pairs, where key is a
 498         column and value represents the width for the column."""
 499         if column is None and not kwargs:
 500             pairs = self.tk.splitlist(self.tk.call(self._w, 'width'))
 501             return dict(pair.split() for pair in pairs)
 502         elif column is not None:
 503             return int(self.tk.call(self._w, 'width', str(column)))
 504 
 505         args = Tkinter._flatten(kwargs.items())
 506         self.tk.call(self._w, 'width', *args)
 507 
 508 
 509     def window_cget(self, index, option):
 510         return self.tk.call(self._w, 'window', 'cget', index, option)
 511 
 512 
 513     def window_configure(self, index, option=None, **kwargs):
 514         """Query or modify options associated with the embedded window given
 515         by index. This should also be used to add a new embedded window into
 516         the table.
 517 
 518         If no option is specified, a dict describing all of the available
 519         options for index is returned. If option is specified, then the
 520         command returns a list describing the one named option. Lastly, if
 521         kwargs is given then it corresponds to option-value pairs that should
 522         be modified."""
 523         if option is None and not kwargs:
 524             return self.tk.call(self._w, 'window', 'configure', index)
 525         elif option:
 526             return self.tk.call(self._w, 'window', 'configure', index,
 527                                 '-%s' % option)
 528         else:
 529             args = ()
 530             for key, val in kwargs.iteritems():
 531                 args += ('-%s' % key, val)
 532 
 533             self.tk.call(self._w, 'window', 'configure', index, *args)
 534 
 535 
 536     def window_delete(self, *indexes):
 537         self.tk.call(self._w, 'window', 'delete', *indexes)
 538 
 539 
 540     def window_move(self, index_from, index_to):
 541         self.tk.call(self._w, 'window', 'move', index_from, index_to)
 542 
 543 
 544     def window_names(self, pattern=None):
 545         return self.tk.call(self._w, 'window', 'names', pattern)
 546 
 547 
 548     def xview(self, index=None):
 549         """If index is not given a tuple containing two fractions is returned,
 550         each fraction is between 0 and 1. Together they describe the
 551         horizontal span that is visible in the window.
 552 
 553         If index is given the view in the window is adjusted so that the
 554         column given by index is displayed at the left edge of the window."""
 555         res = self.tk.call(self._w, 'xview', index)
 556         if index is None:
 557             return self._getdoubles(res)
 558 
 559 
 560     def xview_moveto(self, fraction):
 561         """Adjusts the view in the window so that fraction of the total width
 562         of the table text is off-screen to the left. The fraction parameter
 563         must be a fraction between 0 and 1."""
 564         self.tk.call(self._w, 'xview', 'moveto', fraction)
 565 
 566 
 567     def xview_scroll(self, *L):
 568         #change by frank gao for attach scrollbar 11/11/2010
 569         """Shift the view in the window left or right according to number and
 570         what. The 'number' parameter must be an integer. The 'what' parameter
 571         must be either units or pages or an abbreviation of one of these.
 572 
 573         If 'what' is units, the view adjusts left or right by number cells on
 574         the display; if it is pages then the view adjusts by number screenfuls.
 575         If 'number' is negative then cells farther to the left become visible;
 576         if it is positive then cells farther to the right become visible. """
 577         #self.tk.call(self._w, 'xview', 'scroll', number, what)
 578         if op=='scroll':
 579            units=L[2]
 580            self.tk.call(self._w, 'xview', 'scroll',howMany,units)
 581         elif op=='moveto':
 582                  self.tk.call(self._w, 'xview', 'moveto',howMany)
 583 
 584 
 585     def yview(self, index=None):
 586         """If index is not given a tuple containing two fractions is returned,
 587         each fraction is between 0 and 1. The first element gives the position
 588         of the table element at the top of the window, relative to the table
 589         as a whole. The second element gives the position of the table element
 590         just after the last one in the window, relative to the table as a
 591         whole.
 592 
 593         If index is given the view in the window is adjusted so that the
 594         row given by index is displayed at the top of the window."""
 595         res = self.tk.call(self._w, 'yview', index)
 596         if index is None:
 597             return self._getdoubles(res)
 598 
 599 
 600     def yview_moveto(self, fraction):
 601         """Adjusts the view in the window so that the element given by
 602         fraction appears at the top of the window. The fraction parameter
 603         must be a fraction between 0 and 1."""
 604         self.tk.call(self._w, 'yview', 'moveto', fraction)
 605 
 606 
 607     def yview_scroll(self, *L):
 608         #change by frank gao for attach scrollbar 11/11/2010
 609         """Adjust the view in the window up or down according to number and
 610         what. The 'number' parameter must be an integer. The 'what' parameter
 611         must be either units or pages or an abbreviation of one of these.
 612 
 613         If 'what' is units, the view adjusts up or down by number cells; if it
 614         is pages then the view adjusts by number screenfuls.
 615         If 'number' is negative then earlier elements become visible; if it
 616         is positive then later elements become visible. """
 617         #self.tk.call(self._w, 'yview', 'scroll', number, what)
 618         op,howMany=L[0],L[1]
 619         if op=='scroll':
 620            units=L[2]
 621            self.tk.call(self._w, 'yview', 'scroll',howMany,units)
 622         elif op=='moveto':
 623                  self.tk.call(self._w, 'yview', 'moveto',howMany)
 624 
 625 
 626 # Sample test taken from tktable cvs, original tktable python wrapper
 627 def sample_test():
 628     from Tkinter import Tk, Label, Button
 629 
 630     def test_cmd(event):
 631         if event.i == 0:
 632             return '%i, %i' % (event.r, event.c)
 633         else:
 634             return 'set'
 635 
 636     def browsecmd(event):
 637         print "event:", event.__dict__
 638         print "curselection:", test.curselection()
 639         print "active cell index:", test.index('active')
 640         print "active:", test.index('active', 'row')
 641         print "anchor:", test.index('anchor', 'row')
 642 
 643     root = Tk()
 644 
 645     var = ArrayVar(root)
 646     for y in range(-1, 4):
 647         for x in range(-1, 5):
 648             index = "%i,%i" % (y, x)
 649             var[index] = index
 650 
 651     label = Label(root, text="Proof-of-existence test for Tktable")
 652     label.pack(side = 'top', fill = 'x')
 653 
 654     quit = Button(root, text="QUIT", command=root.destroy)
 655     quit.pack(side = 'bottom', fill = 'x')
 656 
 657     test = Table(root,
 658                  rows=10,
 659                  cols=5,
 660                  state='disabled',
 661                  width=6,
 662                  height=6,
 663                  titlerows=1,
 664                  titlecols=1,
 665                  roworigin=-1,
 666                  colorigin=-1,
 667                  selectmode='browse',
 668                  selecttype='row',
 669                  rowstretch='unset',
 670                  colstretch='last',
 671                  browsecmd=browsecmd,
 672                  flashmode='on',
 673                  variable=var,
 674                  usecommand=0,
 675                  command=test_cmd)
 676     test.pack(expand=1, fill='both')
 677     test.tag_configure('sel', background = 'yellow')
 678     test.tag_configure('active', background = 'blue')
 679     test.tag_configure('title', anchor='w', bg='red', relief='sunken')
 680     root.mainloop()
 681 
 682 if __name__ == '__main__':
 683     sample_test()

tktable.png

tkinter: TkTableWrapper (last edited 2011-03-07 11:07:32 by GuilhermePolo)