[Tkinter-discuss] Tix Grid question, was: Re: Is this the right place for Tix questions?

Michael Lange klappnase at web.de
Tue Apr 22 12:35:39 CEST 2014


Hi,

On Mon, 21 Apr 2014 16:26:26 +0100 (BST)
ALAN GAULD <alan.gauld at btinternet.com> wrote:

(...)
> The Tcl version works fine but the Python version gives an error
> although it does display but without any grid/border formatting. The
> error I get is:
> 
> Exception in Tkinter callback
> Traceback (most recent call last):
>   File "/usr/lib/python3.2/tkinter/__init__.py", line 1402, in __call__
>     return self.func(*args)
>   File "tixgrid-test.py", line 10, in simpleFormat
>     grd.format('grid', x1,y1,x2,y2, anchor='se', fill=0,
> relief='raised', File "/usr/lib/python3.2/tkinter/tix.py", line 341, in
> __getattr__ raise AttributeError(name)
> AttributeError: format
(...)

A couple of years ago I have been playing around with this.
IIRC some of the tixGrid's method are not implemented in the Python
wrapper, probably because they are (were?) not documented in the
tixGrid man page. According to
http://tix.sourceforge.net/man/html/TixCmd/tixGrid.htm#M32
this is still the case for the format, index, selection and a number
of other commands. Back then I wrote myself a custom Tix module with the
missing Grid methods included, as far as I remember it served me well.
I'll copy'n'paste my custom Grid class below, in case you have a use for
it (but of course without warranty ;)

Regards

Michael

###############################################################

class Grid(TixWidget):
    '''The Tix Grid command creates a new window  and makes it into a
    tixGrid widget. Additional options, may be specified on the command
    line or in the option database to configure aspects such as its cursor
    and relief.

    A Grid widget displays its contents in a two dimensional grid of cells.
    Each cell may contain one Tix display item, which may be in text,
    graphics or other formats. See the DisplayStyle class for more information
    about Tix display items. Individual cells, or groups of cells, can be
    formatted with a wide range of attributes, such as its color, relief and
    border.

    Subwidgets - None
    
        STANDARD OPTIONS
            background borderwidth cursor font foreground height
            highlightbackground highlightcolor highlightthickness padx pady
            relief selectbackground selectborderwidth selectforeground
            state takefocus width xscrollcommand yscrollcommand

        WIDGET-SPECIFIC OPTIONS
            editdonecmd - If  non-empty,  gives a Tcl command to be executed when the user
                has edited a grid cell. When this command is called, it is  passed
                with two additional parameters: column, row, where (column, row) is the location
                of the cell that has just been edited.
            editnotifycmd - If non-empty, gives a Tcl command to be executed when  the  user
                tries  to  edit  a grid cell. When this command is called, it is
                passed with two additional parameters: column, row, where (column, row) is  the
                location  of  the  cell.  This  command  should return a boolean
                value: true indicates that the cell is editable and false  oth-
                erwise.
            floatingcols - ??? Requires a boolean. The default value is 0. ???
            floatingrows - ??? Requires a boolean. The default value is 0. ???
            formatcmd - If  non-empty,  gives a Tcl command to be executed when the grid
                cells need to be formatted on the screen. Normally, this command
                calls  the  format() widget command (see below). When this command
                is called, it is passed with five additional parameters: type x1
                y1 x2 y2. type gives the logical type of the region in the grid.
                It may be one of the following. "x-region": the horizontal margin (as defined with topmargin);
                "y-region":  the vertical margin (as defined with leftmargin); "s-region", the area where the
                horizontal and vertical margins are joined; "main": all the  cells
                that  do not fall into the above three types.  x1 y1 x2 y2 gives
                the extent of the region that needs formatting.
            itemtype - ??? the default type of newly created grid cell items; may be "text" or "image";
                default is "text" ???
            leftmargin - In the number of cells, gives the width of  vertical  margin.  A
                zero indicates that no vertical should be drawn (default: 1).
                Defines the number of columns that are fixed when the widget is horizontally
                scrolled. These column(s) can be used as label(s) for the row(s).
            selectmode - Specifies  one of several styles for manipulating the selection.
                The value of the option may be arbitrary, but the default  bind-
                ings  expect  it  to  be  either  single,  browse,  multiple, or
                extended; the default value is single.
            selectunit - Specifies the selection unit. Valid values are "cell",  "column"  or "row".
            sizecmd - ??? A command that is called whenever a grid cell is resized ???
            topmargin - In the number of cells, gives the height of horizontal margin. A
                zero indicates that no horizontal should be drawn (default: 1).
                Defines the number of rows that are fixed when the widget is vertically scrolled.
                These row(s) can be used as label(s) for the column(s).

    '''
    def __init__(self, master, cnf={}, **kw):
        TixWidget.__init__(self, master, 'tixGrid', ['options'], cnf, kw)
    
    def anchor_clear(self):
        '''Clears the selection anchor.'''
        self.tk.call(self._w, 'anchor', 'clear')
    
    def anchor_get(self):
        '''Return a tuple of the form (column, row) describing the cell that is the current selection anchor.'''
        return self._getints(self.tk.call(self._w, 'anchor', 'get'))
    
    def anchor_set(self, column, row):
        '''Set the selection anchor to the cell at (column, row).'''
        self.tk.call(self._w, 'anchor', 'set', column, row)
    
    def bdtype(self, x, y, xbdWidth=None, ybdWidth=None):
        '''?????'''
        # FIXME
        # what is this for?
        return self.tk.call(self._w, 'bdtype', x, y, xbdWidth, ybdWidth)
    
    def delete_column(self, from_, to=None):
        '''If TO is not given, deletes  a  single
        column at the position FROM. If TO is given, deletes
        the range of columns from position FROM through TO.'''
        self.tk.call(self._w, 'delete', 'column', from_, to)
    
    def delete_row(self, from_, to=None):
        '''If TO is not given, deletes  a  single
        row  at the position FROM. If TO is given, deletes
        the range of rows from position FROM through TO.'''
        self.tk.call(self._w, 'delete', 'row', from_, to)
    
    # FIXME: dragsite and dropsite are not documented, but they seem to do at least *something*
    def dragsite_clear(self):
        self.tk.call(self._w, 'dragsite', 'clear')
    
    def dragsite_get(self):
        return self._getints(self.tk.call(self._w, 'dragsite', 'get'))
    
    def dragsite_set(self, x, y):
        self.tk.call(self._w, 'dragsite', 'set', x, y)
    
    def dropsite_clear(self):
        self.tk.call(self._w, 'dropsite', 'clear')
    
    def dropsite_get(self):
        return self._getints(self.tk.call(self._w, 'dropsite', 'get'))
    
    def dropsite_set(self, x, y):
        self.tk.call(self._w, 'dropsite', 'set', x, y)
    
    def edit_apply(self):
        '''If any cell is being edited, de-highlight the cell  and  applies
        the changes.'''
        self.tk.call(self._w, 'edit', 'apply')
    
    def edit_set(self, column, row):
        '''Highlights  the  cell  at  (column, row) for editing, if the -editnotify
        command returns True for this cell.'''
        self.tk.call(self._w, 'edit', 'set', column, row)
    
    def entrycget(self, column, row, option):
        '''Returns the current value of the configuration option  given  by
        OPTION  of  the cell at (column, row). OPTION may have any of the values
        accepted by the set() widget command.'''
        return self.tk.call(self._w, 'entrycget', column, row, '-'+option)
    
    def entryconfigure(self, column, row, cnf=None, **kw):
        '''Query or modify the configuration options of the cell at  (x,y).
        If  no option is specified, returns a list describing all of the
        available options for  the  cell  (see  Tk_ConfigureInfo(n)  for
        information on the format of this list.)  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 correspond-
        ing 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 widget option(s) to have the given  value(s);
        in  this  case  the command returns an empty string.  Option may
        have any of the values accepted by the set() widget command.'''
        return self._configure(('entryconfigure', column, row), cnf, kw)
    entryconfig = entryconfigure
    
    def format_border(self, col0, row0, col1, row1, **kw):
        '''The format_border() method can only be called by the formatcmd callback of the widget.
        Formats the border of the grid cells from (col0, row0) through (col1, row1).
        Possible options are:
            filled - boolean
            xon - boolean
            xoff - boolean
            yon - boolean
            yoff - boolean
            relief, bg, bd, selectbackground etc. ???'''
        self.tk.call(self._w, 'format', 'border', col0, row0, col1, row1, *self._options({}, kw))
    
    def format_grid(self, col0, row0, col1, row1, **kw):
        '''The format_grid() method can only be called by the formatcmd callback of the widget.
        Formats the grid cells from (col0, row0) through (col1, row1).
        Possible options are:
            bordercolor - color
            filled - boolean
            xon - boolean
            xoff - boolean
            yon - boolean
            yoff - boolean
            bg, selectbackground, anchor etc ????'''
        self.tk.call(self._w, 'format', 'grid', col0, row0, col1, row1, *self._options({}, kw))
    
    # FIXME: geometryinfo is not documented, and though it seems to work I cannot
    # find the use of this command
    def geometryinfo(self, width=None, height=None):
        '''?????'''
        # has this really to be done like this?
        return tuple([self._getdoubles(x) for x in self.tk.split(self.tk.call(self._w, 'geometryinfo', width, height))])
    
    def index(self, column, row):
        '''Return a tuple of the form (column, row) describing the grid cell at index (column, row).
        COLUMN and ROW may be "max" (i.e. the last defined column resp. row) or "end" (i.e. max + 1). (???)'''
        # FIXME
        # COLUMN or ROW may be "end" or "max" instead of a numerical index; is this all of this method's use?
        return self._getints(self.tk.call(self._w, 'index', column, row))
    
    # FIXME: info is not documented, maybe because info_bbox() does not seem to have any effect
    # info_exists seems to work well
    def info_bbox(self, column, row):
        '''???'''
        return self._getints(self.tk.call(self._w, 'info', 'bbox', column, row))
    
    def info_exists(self, column, row):
        '''Returns True if the cell at COLUMN and ROW exists, else returns False.'''
        return self._getboolean(self.tk.call(self._w, 'info', 'exists', column, row))
    
    def move_column(self, from_, to, offset):
        '''Moves the the range of columns
        from position FROM through TO by the distance indicated by OFFSET.
        For example, move_column(2, 4, 1) moves the columns 2,3,4 to columns 3,4,5.'''
        self.tk.call(self._w, 'move', 'column', from_, to, offset)
    
    def move_row(self, from_, to, offset):
        '''Moves the the range of rows
        from position FROM through TO by the distance indicated by OFFSET.
        For example, move_row(2, 4, 1) moves the rows 2,3,4 to rows 3,4,5.'''
        self.tk.call(self._w, 'move', 'row', from_, to, offset)
    
    # FIXME: this is not documented, but seems to work
    def nearest(self, x, y):
        '''Returns a tuple of the form (column, row) describing the grid cell
        nearest to window coordinates x and y.'''
        return self._getints(self.tk.call(self._w, 'nearest', x, y))
    
    # FIXME: selection methods are not documented in the man page
    # maybe this is because only adjust, set and toggle (and partially clear) seem to work
    def selection_adjust(self, col0, row0, col1=None, row1=None):
        '''Removes the selection from all grid cells and adds the cell at (col0, row0) to the selection;
        if col1 and row1 are given, adds the range of cells from (col0, row0) through (col1, row1) to the selection.'''
        self.tk.call(self._w, 'selection', 'adjust', col0, row0, col1, row1)
    select_adjust = selection_adjust
    
    def selection_clear(self, col0=0, row0=0, col1='max', row1='max'):
        # this seems to work only with selection_clear(0, 0, 'max', 'max'),
        # which removes any selection
        '''Removes the selection from all grid cells.'''
        self.tk.call(self._w, 'select', 'clear', col0, row0, col1, row1)
    select_clear = selection_clear
    
    def selection_includes(self, column, row):
        # this does not seem to have any effect
        '''???Returns True if the grid cell at (column, row) is currently selected,
        else returns False.??? (I guess it should).'''
        return self._getboolean(self.tk.call(self._w, 'selection', 'includes', column, row))
    select_includes = selection_includes

    def selection_set(self, col0, row0, col1=None, row1=None):
        '''Adds the cell at (col0, row0) to the selection; if col1 and row1 are given,
        adds the range of cells from (col0, row0) through (col1, row1) to the selection.'''
        self.tk.call(self._w, 'selection', 'set', col0, row0, col1, row1)
    select_set = selection_set
    
    def selection_toggle(self, col0, row0, col1=None, row1=None):
        '''Changes the state of selection for the cell at (col0, row0); if col1 and row1 are given,
        changes the state of selection for the range of cells from (col0, row0) through (col1, row1).'''
        self.tk.call(self._w, 'selection', 'toggle', col0, row0, col1, row1)
    select_toggle = selection_toggle
    
    def set(self, column, row, **kw):
        '''Creates  a  new  display item at the cell at (column, row). The optional
        -itemtype parameter gives the type of the display item ("text" or "image" ???). An addi-
        tional list of option-value pairs specify options of the display
        item. If a display item already exists at  this  cell,  the  old
        item will be deleted automatically.
        Possible options for text items are:
            text, style, underline
        Possible options for image items are:
            image, style.'''
        self.tk.call(self._w, 'set', column, row, *self._options({}, kw))
    
    def size_column(self, index, **kw):
        '''Queries  or  sets the size of the column given by 
        INDEX.  INDEX may be any  non-negative
        integer  that  gives  the  position  of a given column.
        INDEX can also be the string "default"; in this case, this command
        queries or sets the default size of all columns.
        When  no  option-value  pair is given, this command returns a tuple con-
        taining the current size setting of the given  column.  When
        option-value  pairs  are  given,  the corresponding options of the size
        setting of the given column are changed. Options may be one  of  the  foll-
        wing:
              pad0 pixels
                     Specifies the paddings to the left of a column.
              pad1 pixels
                     Specifies the paddings to the right of a  column.
              size val
                     Specifies  the  width of a column .
                     Val may be: "auto" -- the width of the column  is  set  the
                     the widest cell in the column; a valid Tk screen distance
                     unit (see Tk_GetPixels(n)); or a real number following by
                     the word chars (e.g. 3.4chars) that sets the width of the
                     column to the given number of characters.'''
        return self.tk.split(self.tk.call(self._w, 'size', 'column', index, *self._options({}, kw)))
    
    def size_row(self, index, **kw):
        '''Queries  or  sets the size of the row given by 
        INDEX. INDEX may be any  non-negative
        integer  that  gives  the  position  of a given row .
        INDEX can also be the string "default"; in this case, this command
        queries or sets the default size of all rows.
        When  no  option-value  pair is given, this command returns a list con-
        taining the current size setting of the given  row .  When
        option-value  pairs  are  given,  the corresponding options of the size
        setting of the given row are changed. Options may be one  of  the  foll-
        wing:
              pad0 pixels
                     Specifies the paddings to the top of a row.
              pad1 pixels
                     Specifies the paddings to the the bottom of a row.
              size val
                     Specifies  the height of a row.
                     Val may be: "auto" -- the height of the row  is  set  the
                     the highest cell in the row; a valid Tk screen distance
                     unit (see Tk_GetPixels(n)); or a real number following by
                     the word chars (e.g. 3.4chars) that sets the height of the
                     row to the given number of characters.'''
        return self.tk.split(self.tk.call(self._w, 'size', 'row', index, *self._options({}, kw)))
    
    # FIXME: sort is not documented, but the the widget accepts the command
    # and it seems to work at least for the most part
    def sort_column(self, first, last, **kw):
        '''Sorts columns in the range from FIRST through LAST, according to the given options.
        Possible options are:
            command : a tcl command that accepts two items as arguments, compares these and returns a proper boolean value.
            key     : the index of the row to compare the items' values from.
            order   : must be "increasing" or "decreasing".
            type    : must be "ascii", "integer" or "real".'''
        self.tk.call(self._w, 'sort', 'column', first, last, *self._options({}, kw))
    
    def sort_row(self, first, last, **kw):
        '''Sorts rows in the range from FIRST through LAST, according to the given options.
        Possible options are:
            command : a tcl command that accepts two items as arguments, compares these and returns a proper boolean value.
            key     : the index of the column to compare the items' values from.
            order   : must be "increasing" or "decreasing".
            type    : must be "ascii", "integer" or "real".'''
        self.tk.call(self._w, 'sort', 'row', first, last, *self._options({}, kw))
    
    def unset(self, column, row):
        '''Clears the cell at (column, row) by removing its display item.'''
        self.tk.call(self._w, 'unset', column, row)

    def xview(self, *what):
        """Query and change horizontal position of the view."""
        if not what:
            return self._getdoubles(self.tk.call(self._w, 'xview'))
        self.tk.call((self._w, 'xview') + what)
        
    def xview_moveto(self, fraction):
        """Adjust the view in the window so that FRACTION of the
        total width of the entry is off-screen to the left."""
        self.tk.call(self._w, 'xview', 'moveto', fraction)
        
    def xview_scroll(self, number, what):
        """Shift the x-view according to NUMBER which is measured in "units" or "pages" (WHAT)."""
        self.tk.call(self._w, 'xview', 'scroll', number, what)
        
    def yview(self, *what):
        """Query and change vertical position of the view."""
        if not what:
            return self._getdoubles(self.tk.call(self._w, 'yview'))
        self.tk.call((self._w, 'yview') + what)
        
    def yview_moveto(self, fraction):
        """Adjust the view in the window so that FRACTION of the
        total width of the entry is off-screen to the top."""
        self.tk.call(self._w, 'yview', 'moveto', fraction)
        
    def yview_scroll(self, number, what):
        """Shift the y-view according to NUMBER which is measured in "units" or "pages" (WHAT)."""
        self.tk.call(self._w, 'yview', 'scroll', number, what)
        
class _dummyGrid(Grid, TixSubWidget):
    def __init__(self, master, name, destroy_physically=1):
        TixSubWidget.__init__(self, master, name, destroy_physically)

class ScrolledGrid(TixWidget):
    '''Scrolled Grid widgets'''
    # FIXME: It should inherit -superclass tixScrolledWidget
    def __init__(self, master, cnf={}, **kw):
        TixWidget.__init__(self, master, 'tixScrolledGrid', ['options'], cnf, kw)
        self.subwidget_list['grid'] = _dummyGrid(self, 'grid')
        self.subwidget_list['vsb'] = _dummyScrollbar(self, 'vsb')
        self.subwidget_list['hsb'] = _dummyScrollbar(self, 'hsb')
        # we cannot use the self.grid shortcut to access the Grid subwidget here
        # because it conflicts with the grid() geometry method, so add a grid_ attribute as a replacement
        self.grid_ = self.subwidget('grid')



###############################################################


.-.. .. ...- .   .-.. --- -. --.   .- -. -..   .--. .-. --- ... .--. . .-.

Vulcans do not approve of violence.
		-- Spock, "Journey to Babel", stardate 3842.4


More information about the Tkinter-discuss mailing list