[pygtk] question about a updating a textview as an object

Brian dol-sen at telus.net
Thu Oct 19 14:16:38 WST 2006


On Wed, 2006-18-10 at 23:50 -0500, shawn bright wrote:
> hey there.
> i have a gtk GUI app that uses 4 text views to update info from 4
> different threads. the code i use to update the view is this.
> 
> def buffer_add(self,  input_data, buffer, textview):
>         self.buffer.insert (self.buffer.get_end_iter(), input_data)
>         if self.buffer.get_line_count() > 400:
>             self.buffer.delete(self.buffer.get_start_iter(),
>                                 self.buffer.get_iter_at_line (200))
>         mark = self.buffer.create_mark("end",
>                                 self.buffer.get_end_iter(), False)
>         self.textview.scroll_to_mark(mark, 0.05, True, 0.0, 1.0)
> 
> now, i have the same function in all four threads. Each updates a
> different textview. 
> the threads run in a class threading.thread. 
>  
> the code that calls them is like this.
> 
> S1 = Serial1(self.Input1Buffer, self.TTYS14View)
> S1.start()
> 
> each thread has some initial code like this
> 
> class Serial1(threading.Thread):
>     def __init__(self, buffer, textview):
>         threading.Thread.__init__(self)
>         self.buffer = buffer
>         self.iter = self.buffer.get_end_iter()
>         self.textview = textview
> 
> my question is..... from the main app, if i pass the textview and
> buffer to each thread that needs one, can i, from the thread pass
> those as objects to one function that will update the text view? if
> so, do i need to make that function a global object ? or can i just
> declare it at the beginning of the program ? 
> 
> does this question make sense? 
> 
> if you have read this far, i thank you for your time.
> 
> shawn


Yes, you can pass the buffer pointers around. I have done it many times.
No you do not need to make them global.

Updating any gui items from a thread other than the main gui thread is
asking for trouble.  For any thread to safely access the textview buffer
you need to wrap it with calls to gtk to get clearance (sorry, don't
recall the actual function names atm) to modify them without causing
conflicts.  Something that can hold up your thread waiting for the
update to sync with the gui.

A much safer way to go is to gather your info in the threads and then
pass that info back to the main gui thread to update the correct buffer.
A good example of this is using the dispatcher module we've come up with
that handles the inter-thread communication collision free.  see
attached code.  You will see in the example code that the buffer pointer
is passed to the method that appends the text to the buffer.  It should
be easy to modify the example code to use different buffers for each
thread.

I have used global variables in our app which has several notebook tabs
each with their own textview and use the same append method.  I used
global lists to store the buffer pointers and pass the index number to
the append module as there are several other things that use the index
number as well.  Word of caution if you intend on using a list to store
the pointers use the list.append() to add them to an empty list, don't
initialize the list like:

buffer_list = [None, None] # it won't work

buffer_list = [] # works
buffer_list.append(buffer_pointer1)
buffer_list.append(buffer_pointer2)


code snipit:

    def append(self, num, text, tagname = None):
        """ Append text to a text buffer.  Line numbering based on
            the process window line count is automatically added.
            BUT -- if multiple text buffers are going to be updated,
            always update the process buffer LAST to guarantee the
            line numbering is correct.
            Optionally, text formatting can be applied as well
        """
        #dprint("Notebook: overwrite() -- num= " + str(num))
        #dprint(self.current_tab)
        line_number = self.view_buffer[TAB_PROCESS].get_line_count() 
        iter = self.view_buffer[num].get_end_iter()
        lntext = str(line_number).zfill(6) + ' '
        if self.last_text[num].endswith('\n'):
            self.view_buffer[num].insert_with_tags_by_name(iter, lntext, 'linenumber')
        if tagname == None:
            #self.view_buffer[num].insert(iter, text)
            #dprint("Notebook: append(): attempting to set text with tagnames " + str(self.current_tagnames))
            self.view_buffer[num].insert_with_tags_by_name(iter, text, *self.current_tagnames)
        else:
            self.view_buffer[num].insert_with_tags_by_name(iter, text, tagname)
        if self.auto_scroll[num] and num == self.current_tab:
            self.scroll_current_view()
        self.last_text[num] = text

In the dispatcher example you will see that the method

-- 
Brian <dol-sen at telus.net>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: dispatcher.py
Type: text/x-python
Size: 1251 bytes
Desc: not available
Url : http://www.daa.com.au/pipermail/pygtk/attachments/20061018/0493be9b/dispatcher.py
-------------- next part --------------
A non-text attachment was scrubbed...
Name: dispatcher-example.py
Type: text/x-python
Size: 3377 bytes
Desc: not available
Url : http://www.daa.com.au/pipermail/pygtk/attachments/20061018/0493be9b/dispatcher-example.py


More information about the pygtk mailing list