On Thursday 07 October 2004 08:58, Christian Robottom Reis wrote:
> On Thu, Oct 07, 2004 at 01:54:46PM +0200, Xavier Ordoquy wrote:
> > On Thu, 2004-10-07 at 13:46 +0200, Fabien COUTANT wrote:
> > > 
> > > As a GTK 1.2/2.x and PyGtk 0.6/2.x programmer, I think it's worse
> > > than that.  I think the problem about the list widget lies in Gtk,
> > > not in PyGtk.  Once upon a time was the CList widget. It was 
limited
> > > but simple and practical, and suited many needs.  Using it, it was
> > > simple to do simple things, it was moderately complicated to do
> > > moderately complicated things, and it was impossible to do
> > > complicated things.
> > 
> > You should have done some support on irc about that. gtkclist caused 
an
> > enormous amount of questions, noise and annoyances.
> 
> Even so, it was a lot less noise than TreeView. But let's be practical
> here and move on towards something that *is* feasible instead of
> complaining about the past. 
> 
> I think Fabien's complaint is definitely valid: we need a widget that 
is
> simple enough to be used by anyone not wanting to do rocket-science 
with
> their rows. I've balked at the amount of questions and FAQs we get on
> TreeView -- come *on*, the FAQ is *the* indication of a non-trivial 
API.
> 
> There are two possible solutions. One is writing directly to gtk-devel
> and bringing the discussion up. Bringing it up with code in hand is
> definitely going to be more prone to acceptance. It is likely that
> something harnessing off TreeView's code and simply providing a simple
> and unified API would be pretty easy to do and would solve 90% of the
> complexity problems users face. 
> 
> The other solution, perhaps interim, is to do a decent Python wrapper.
> J. Barstow's proposal is a step in the right direction, but it should
> really `look' like a regular GTK+ widget -- that means lowercase,
> underscore-separated method names. I'd say a good attempt would be
> mimicing most of what CList provided:
> 
>     - Providing a list of headers to the constructor
>     - append()/insert() methods that takes a list of strings
>     - A clear() method that deletes all rows
>     - remove() method with removes a numbered row
>     - select/unselect_row() methods that take a numbered row
>     - set_data()/get_data() pairs and a find_row_from_data()
> 
> You'd need to find out if freeze()/thaw() make sense in this new
> context.
> 
> You could from there work on the icing, which is backgrounds, 
controlled
> sorting, column visibility width and title control, pixmap and 
`special
> cell' support if necessary.
> 
> I've heard Python is a good prototyping language, by the way <wink>.


I too got frustrated with trying to use a basic clist in the gtk
2.x. I don't completely understand all the details of the new widget,
but I learned enough to do what I needed to do. I wrote this python
wrapper (not a gtk widget) to help me use it. While it's tailored for
my uses which involved a SQL database, it shouldn't be too difficult
to clean up and extend. If anyone is interested, here it is. I use 4
spaces for indentation, but if it gets garbled, let me know and I can
put it on a website for download.

Dave

-----------------------------------------------------------------

#!/usr/bin/env python

#----------------------------------------------------------------------
# ListStoreComponent.py
# Dave Reed
# 12/17/2002
#----------------------------------------------------------------------

import sys

import gtk, gobject

import UtilPSQL

#----------------------------------------------------------------------

class ListStoreComponent:


    
#----------------------------------------------------------------------

    def __init__(self, tree_view_widget, col_names, col_dict,
                 selection_mode=None):

        """ __init__(self, tree_view_widget, col_names, col_dict):

        col_names = [
            'last_name', 'first_name', 'address1', 'birth_date', 'id'
            ]
        
        col_dict = {
            #            (title, type, width, visible)
            'last_name': ('Last Name', 'str', 120, 1),
            'first_name': ('First Name', 'str', 120, 1),
            'address1': ('Address1', 'str', 150, 1),
            'birth_date': ('Birth Date', 'str', 70, 1),
            'id': ('ID', 'int', 50, 1),
            }


"""

        self.tree_view_widget = tree_view_widget
        self.col_names = col_names
        self.col_dict = col_dict
        self.selected_rows = {}
        self.unselect = None
        self.my_select = 0
        self.changed_row = None
        
        # create list of types for calling gtk.ListStore with
        l = []
        total_width = 0
        for c in col_names:
            title, col_type, width, visible = col_dict[c]
            total_width = total_width + width
            if col_type == 'int':
                col_type = gobject.TYPE_INT
            else: # elif col_type == 'str':
                col_type = gobject.TYPE_STRING
            l.append(col_type)
        l = tuple(l)
        self.model = gtk.ListStore(*l)

        # append columns
        self.tree_view_cols = []
        w = self.tree_view_widget
        for i in range(len(col_names)):
            c = col_names[i]
            cell = gtk.CellRendererText()
            title, col_type, width, visible = col_dict[c]
            col = gtk.TreeViewColumn(title, cell, text=i)
            self.tree_view_cols.append(col)
            w.append_column(col)
            
            # set visibility and size
            col.set_visible(visible)
            col.set_min_width(width)
            
        w.set_model(self.model)
        self.selection = w.get_selection()

        if selection_mode is not None:
            self.selection.set_mode(selection_mode)
            if selection_mode == gtk.SELECTION_MULTIPLE:
                self.handler = self.selection.connect(
                    "changed", self.on_selection_changed)
        
        
    
#----------------------------------------------------------------------

    def clear(self):
        
        self.my_select = 1
        self.model.clear()
        self.my_select = 0
        
    
#----------------------------------------------------------------------

    def sql_populate(self, db, table, where_clause, order_clause,
                     type_dict):
        
        com = ['select ']
        com.append(','.join(self.col_names))
        com.append(' from %s %s %s;' % (table, where_clause, 
order_clause))
        com = ''.join(com)

        self.sql_populate_cmd(db, com, type_dict)
        
    
#----------------------------------------------------------------------

    def sql_populate_cmd(self, db, com, type_dict):

        self.my_select = 1
        # clear existing entries
        self.model.clear()
        
        db.execute(com)
        r = db.fetchall()

        for i in xrange(len(r)):
            line = r[i]
            for j in range(len(self.col_names)):
                c = self.col_names[j]
                if type_dict[c][:7] == 'numeric':
                    dec = type_dict[c].split(',')[1][:-1]
                    format = '%%0.%sf' % dec
                    line[j] = format % line[j]
            iter = self.model.append(line)

        self.tree_view_widget.set_model(self.model)
        self.selected_rows = {}
        self.my_select = 0
        
    
#----------------------------------------------------------------------

    def populate_with_list(self, row_list):

        self.my_select = 1
        # clear existing entries
        self.model.clear()

        # new method for use with pygtk in CVS
        for i in xrange(len(row_list)):
            iter = self.model.append(row_list[i])
                
        self.tree_view_widget.set_model(self.model)
        self.selected_rows = {}
        self.my_select = 0
        
    
#----------------------------------------------------------------------

    def append_row(self, row_data):

        # new method for use with pygtk in CVS
        self.model.append(row_data)
        
    
#----------------------------------------------------------------------

    def get_row(self, row_num):
        
        if row_num < len(self.model):
            row = self.model[row_num]
            d = {}
            for i in range(len(self.col_names)):
                c = self.col_names[i]
                d[c] = row[i]
            return d
        else:
            return None
    
    
#----------------------------------------------------------------------
    # code for handling multi selection without having to also press
    # the control key
    
    def on_selection_changed(self, selection):

        if not self.my_select:
            selection.selected_foreach(self.select_row)
            r = self.changed_row
            self.my_select = 1
            if self.selected_rows.has_key(r):
                del self.selected_rows[r]
                self.unselect = 1
                selection.unselect_iter(self.model[r].iter)
            else:
                self.selected_rows[r] = r
                
            # select the appropriate rows
            selection.disconnect(self.handler)
            self.unselect = 0
            for i in self.selected_rows:
                if i != r:
                    selection.select_iter(self.model[i].iter)
            self.my_select = 0
            self.handler = selection.connect(
                "changed", self.on_selection_changed)

    
#----------------------------------------------------------------------

    def select_row(self, list_store, row, iter):
        self.changed_row = row[0]
                
    
#----------------------------------------------------------------------

    def get_selected_row(self):
        try:
            selection = self.tree_view_widget.get_selection()
            model, iter = selection.get_selected()
            if selection.iter_is_selected(iter):
                row = model[iter]
                d = {}
                for i in range(len(self.col_names)):
                    c = self.col_names[i]
                    d[c] = row[i]
                return d
            else:
                print 'not selected'
                return None
        except:
            return None
        
    
#----------------------------------------------------------------------

    def get_selected_iter(self):
        try:
            selection = self.tree_view_widget.get_selection()
            model, iter = selection.get_selected()
            return iter
        except:
            None
    
    
#----------------------------------------------------------------------

    def select_iter(self, iter):
        selection = self.tree_view_widget.get_selection()
        selection.select_iter(iter)

    
#----------------------------------------------------------------------

        
#----------------------------------------------------------------------

def main(argv):
    pass

#----------------------------------------------------------------------

if __name__ == '__main__':
   main(sys.argv)


_______________________________________________
pygtk mailing list   [EMAIL PROTECTED]
http://www.daa.com.au/mailman/listinfo/pygtk
Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/

Reply via email to