/usr/share/doc/python-gtk2-tutorial/html/sec-TreeModelInterface.html is in python-gtk2-tutorial 2.4-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 | <html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>14.2. The TreeModel Interface and Data Stores</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-TreeViewWidget.html" title="Chapter 14. Tree View Widget"><link rel="previous" href="ch-TreeViewWidget.html" title="Chapter 14. Tree View Widget"><link rel="next" href="sec-TreeViews.html" title="14.3. TreeViews"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">14.2. The TreeModel Interface and Data Stores</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-TreeViewWidget.html">Prev</a> </td><th width="60%" align="center">Chapter 14. Tree View Widget</th><td width="20%" align="right"> <a accesskey="n" href="sec-TreeViews.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-TreeModelInterface"></a>14.2. The TreeModel Interface and Data Stores</h2></div></div><div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-TreeModelIntroduction"></a>14.2.1. Introduction</h3></div></div><div></div></div><p>The <tt class="classname">TreeModel</tt> interface is implemented by
all the <tt class="classname">TreeModel</tt> subclasses and provides methods
to:</p><div class="itemizedlist"><ul type="disc"><li>retrieve the characteristics of the data store such as
the number of columns and the type of data in a column.</li><li>retrieve a <tt class="classname">TreeIter</tt> (a transient
reference) that points at a row in the model</li><li>retrieve information about a node (or row) such as the
number of its child nodes, a list of its child nodes, the contents of its
columns and a pointer to its parent node</li><li>provide notification of <tt class="classname">TreeModel</tt>
data changes</li></ul></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-CreatingTreeStoreAndListStore"></a>14.2.2. Creating TreeStore and ListStore Objects</h3></div></div><div></div></div><p>The base data store classes: <tt class="classname">ListStore</tt> and
<tt class="classname">TreeStore</tt> provide the means to define and manage the
rows and columns of data in the tree model. The constructors of both these
objects require the column types to be specified as any of:</p><div class="itemizedlist"><ul type="disc"><li>Python types such as the built-in types: int, str, long,
float and object</li><li>PyGTK types such as <tt class="classname">Button</tt>,
<tt class="classname">VBox</tt>, <tt class="classname">gdk.Rectangle</tt>,
<tt class="classname">gdk.Pixbuf</tt></li><li><p><tt class="classname">GObject</tt> types (GTK+ GTypes)
specified either as GObject Type constants or as strings. Most GTypes are
mapped to a Python type:</p><div class="itemizedlist"><ul type="circle"><li>gobject.TYPE_CHAR or 'gchar'</li><li>gobject.TYPE_UCHAR or 'guchar'</li><li>gobject.TYPE_BOOLEAN or 'gboolean'</li><li>gobject.TYPE_INT or 'gint'</li><li>gobject.TYPE_UINT or 'guint'</li><li>gobject.TYPE_LONG or 'glong</li><li>gobject.TYPE_ULONG or 'gulong</li><li>gobject.TYPE_INT64 or 'gint64'</li><li>gobject.TYPE_UINT64 or 'guint64'</li><li>gobject.TYPE_FLOAT or 'gfloat'</li><li>gobject.TYPE_DOUBLE or 'gdouble'</li><li>gobject.TYPE_STRING or 'gchararray'</li><li>gobject.TYPE_OBJECT or 'GObject</li></ul></div></li></ul></div><p>For example to create a <tt class="classname">ListStore</tt> or
<tt class="classname">TreeStore</tt> with rows containing a
<tt class="classname">gdk.Pixbuf</tt>, an integer, a string and boolean you
could do something like:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
liststore = ListStore(gtk.gdk.Pixbuf, int, str, 'gboolean')
treestore = TreeStore(gtk.gdk.Pixbuf, int, str, 'gboolean')
</pre></td></tr></table><p>Once a <tt class="classname">ListStore</tt> or
<tt class="classname">TreeStore</tt> is created and its columns defined, they
cannot be changed or modified. It's also important to realize that there is
no preset relation between the columns in a <tt class="classname">TreeView</tt>
and the columns of its <tt class="classname">TreeModel</tt>. That is, the fifth
column of data in a <tt class="classname">TreeModel</tt> may be displayed in the
first column of one <tt class="classname">TreeView</tt> and in the third column
in another. So you don't have to worry about how the data will be displayed
when creating the data store.</p><p>If these two data stores do not fit your application it is
possible to define your own custom data store in Python as long as it
implements the TreeModel interface. I'll talk more about this later in <a href="sec-GenericTreeModel.html" title="14.11. The Generic TreeModel">Section 14.11, “The Generic TreeModel”</a>.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-ReferringToTreeModelRows"></a>14.2.3. Referring to TreeModel Rows</h3></div></div><div></div></div><p>Before we can talk about managing the data rows in a
<tt class="classname">TreeStore</tt> or <tt class="classname">ListStore</tt> we need
a way of specifying which row we want to deal with. PyGTK has three ways of
referring to <tt class="classname">TreeModel</tt> rows: a tree path, a
<tt class="classname">TreeIter</tt> and a
<tt class="classname">TreeRowReference</tt>.</p><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-TreePaths"></a>14.2.3.1. Tree Paths</h4></div></div><div></div></div><p>A tree path is a int, string or tuple representation of the
location of a row in the store. An int value specifies the top level row in
the model starting from 0. For example, a tree path value of 4 would specify
the fifth row in the store. By comparison, a string representation of the
same row would be "4" and the tuple representation would be (4,). This is
sufficient for specifying any row in a <tt class="classname">ListStore</tt> but
for a TreeStore we have to be able to represent the child rows. For these
cases we have to use either the string or tuple representations.</p><p>Since a <tt class="classname">TreeStore</tt> can have an arbitrarily
deep hierarchy the string representation specifies the path from the top
level to the designated row using ints separated by the ":"
character. Similarly, the tuple representation specifies the tree path
starting from the top level to the row as a sequence of ints. For example,
valid tree path string representations are: "0:2" (specifies the row that is
the third child of the first row) and "4:0:1" (specifies the row that is the
second child of the first child of the fifth row). By comparison the same
tree paths are represented by the tuples (0, 2) and (4, 0, 1)
respectively.</p><p>A tree path provides the only way to map from a
<tt class="classname">TreeView</tt> row to a <tt class="classname">TreeModel</tt>
row because the tree path of a <tt class="classname">TreeView</tt> row is the
same as the tree path of the corresponding <tt class="classname">TreeModel</tt>
row. There are also some problems with tree paths:</p><div class="itemizedlist"><ul type="disc"><li>a tree path can specify a row that doesn't exist in the
ListStore or TreeStore.</li><li>a tree path can point to a different data row after
inserting or deleting a row in the <tt class="classname">ListStore</tt> or
<tt class="classname">TreeStore</tt>.</li></ul></div><p>PyGTK uses the tuple representation when returning tree paths
but will accept any of the three forms for a tree path representation. You
should use the tuple representation for a tree path for consistency.</p><p>A tree path can be retrieved from a
<tt class="classname">TreeIter</tt> using the
<tt class="methodname">get_path</tt>() method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
path = store.get_path(<b class="parameter"><tt>iter</tt></b>)
</pre></td></tr></table><p>where <i class="parameter"><tt>iter</tt></i> is a
<tt class="classname">TreeIter</tt> pointing at a row in store and
<i class="parameter"><tt>path</tt></i> is the row's tree path as a tuple.</p></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-TreeIters"></a>14.2.3.2. TreeIters</h4></div></div><div></div></div><p>A <tt class="classname">TreeIter</tt> is an object that provides a
transient reference to a <tt class="classname">ListStore</tt> or
<tt class="classname">TreeStore</tt> row. If the contents of the store change
(usually because a row is added or deleted) the
<tt class="classname">TreeIter</tt>s can become invalid. A
<tt class="classname">TreeModel</tt> that supports persistent TreeIters should
set the <tt class="literal">gtk.TREE_MODEL_ITERS_PERSIST</tt> flag. An application
can check for this flag using the <tt class="methodname">get_flags</tt>()
method.</p><p>A <tt class="classname">TreeIter</tt> is created by one of the
<tt class="classname">TreeModel</tt> methods that are applicable to both
<tt class="classname">TreeStore</tt> and <tt class="classname">ListStore</tt>
objects:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
treeiter = store.get_iter(<b class="parameter"><tt>path</tt></b>)
</pre></td></tr></table><p>where <i class="parameter"><tt>treeiter</tt></i> points at the row at the
tree path <i class="parameter"><tt>path</tt></i>. The ValueError exception is raised if
the tree path is invalid.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
treeiter = store.get_iter_first()
</pre></td></tr></table><p>where <i class="parameter"><tt>treeiter</tt></i> is a TreeIter pointing
at the row at tree path (0,). <i class="parameter"><tt>treeiter</tt></i> will be
<tt class="literal">None</tt> if the store is empty.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
treeiter = store.iter_next(<b class="parameter"><tt>iter</tt></b>)
</pre></td></tr></table><p>where <i class="parameter"><tt>treeiter</tt></i> is a
<tt class="classname">TreeIter</tt> that points at the next row at the same
level as the <tt class="classname">TreeIter</tt> specified by
<i class="parameter"><tt>iter</tt></i>. <i class="parameter"><tt>treeiter</tt></i> will be
<tt class="literal">None</tt> if there is no next row (<i class="parameter"><tt>iter</tt></i>
is also invalidated).</p><p>The following methods are useful only for retrieving a
<tt class="classname">TreeIter</tt> from a
<tt class="classname">TreeStore</tt>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
treeiter = treestore.iter_children(<b class="parameter"><tt>parent</tt></b>)
</pre></td></tr></table><p>where <i class="parameter"><tt>treeiter</tt></i> is a
<tt class="classname">TreeIter</tt> pointing at the first child row of the row
specified by the <tt class="classname">TreeIter</tt>
<i class="parameter"><tt>parent</tt></i>. <i class="parameter"><tt>treeiter</tt></i> will be
<tt class="literal">None</tt> if there is no child.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
treeiter = treestore.iter_nth_child(<b class="parameter"><tt>parent</tt></b>, <b class="parameter"><tt>n</tt></b>)
</pre></td></tr></table><p>where <i class="parameter"><tt>treeiter</tt></i> is a
<tt class="classname">TreeIter</tt> pointing at the child row (with the index
<i class="parameter"><tt>n</tt></i>) of the row specified by the
<tt class="classname">TreeIter</tt>
<i class="parameter"><tt>parent</tt></i>. <i class="parameter"><tt>parent</tt></i> may be
<tt class="literal">None</tt> to retrieve a top level
row. <i class="parameter"><tt>treeiter</tt></i> will be <tt class="literal">None</tt> if
there is no child.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
treeiter = treestore.iter_parent(<b class="parameter"><tt>child</tt></b>)
</pre></td></tr></table><p>where <i class="parameter"><tt>treeiter</tt></i> is a
<tt class="classname">TreeIter</tt> pointing at the parent row of the row
specified by the <tt class="classname">TreeIter</tt>
<i class="parameter"><tt>child</tt></i>. treeiter will be <tt class="literal">None</tt> if
there is no child.</p><p>A tree path can be retrieved from a
<tt class="classname">TreeIter</tt> using the
<tt class="methodname">get_path</tt>() method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
path = store.get_path(<b class="parameter"><tt>iter</tt></b>)
</pre></td></tr></table><p>where <i class="parameter"><tt>iter</tt></i> is a
<tt class="classname">Treeiter</tt> pointing at a row in store and
<i class="parameter"><tt>path</tt></i> is the row's tree path as a tuple.</p></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-TreeRowReferences"></a>14.2.3.3. TreeRowReferences</h4></div></div><div></div></div><p>A <tt class="classname">TreeRowReference</tt> is a persistent
reference to a row of data in a store. While the tree path (i.e. the
location) of the row might change as rows are added to or deleted from the
store, the <tt class="classname">TreeRowReference</tt> will point at the same
data row as long as it exists.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p><tt class="classname">TreeRowReference</tt>s are only available in
PyGTK 2.4 and above.</p></div><p>You can create a <tt class="classname">TreeRowReference</tt> using
its constructor:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
treerowref = TreeRowReference(<b class="parameter"><tt>model</tt></b>, <b class="parameter"><tt>path</tt></b>)
</pre></td></tr></table><p>where <i class="parameter"><tt>model</tt></i> is the
<tt class="classname">TreeModel</tt> containing the row and
<i class="parameter"><tt>path</tt></i> is the tree path of the row to track. If
<i class="parameter"><tt>path</tt></i> isn't a valid tree path for
<i class="parameter"><tt>model</tt></i>, <tt class="literal">None</tt> is returned.</p></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-AddingStoreRows"></a>14.2.4. Adding Rows</h3></div></div><div></div></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-AddingListStoreRows"></a>14.2.4.1. Adding Rows to a ListStore</h4></div></div><div></div></div><p>Once you have a <tt class="classname">ListStore</tt> you'll need to
add data rows using one of the following methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
iter = append(<b class="parameter"><tt>row</tt></b>=None)
iter = prepend(<b class="parameter"><tt>row</tt></b>=None)
iter = insert(<b class="parameter"><tt>position</tt></b>, <b class="parameter"><tt>row</tt></b>=None)
iter = insert_before(<b class="parameter"><tt>sibling</tt></b>, <b class="parameter"><tt>row</tt></b>=None)
iter = insert_after(<b class="parameter"><tt>sibling</tt></b>, <b class="parameter"><tt>row</tt></b>=None)
</pre></td></tr></table><p>Each of these methods inserts a row at an implied or specified
position in the <tt class="classname">ListStore</tt>. The
<tt class="methodname">append</tt>() and <tt class="methodname">prepend</tt>()
methods use implied positions: after the last row and before the first row,
respectively. The <tt class="methodname">insert</tt>() method takes an integer
(the parameter <i class="parameter"><tt>position</tt></i>) that specifies the location
where the row will be inserted. The other two methods take a
<tt class="classname">TreeIter</tt> (<i class="parameter"><tt>sibling</tt></i>) that
references a row in the <tt class="classname">ListStore</tt> to insert the row
before or after.</p><p>The <i class="parameter"><tt>row</tt></i> parameter specifies the data that
should be inserted in the row after it is created. If
<i class="parameter"><tt>row</tt></i> is <tt class="literal">None</tt> or not specified, an
empty row will be created. If <i class="parameter"><tt>row</tt></i> is specified it
must be a tuple or list containing as many items as the number of columns in
the <tt class="classname">ListStore</tt>. The items must also match the data
type of their respective <tt class="classname">ListStore</tt> columns.</p><p>All methods return a <tt class="classname">TreeIter</tt> that points
at the newly inserted row. The following code fragment illustrates the
creation of a <tt class="classname">ListStore</tt> and the addition of data rows
to it:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
...
liststore = gtk.ListStore(int, str, gtk.gdk.Color)
liststore.append([0,'red',colormap.alloc_color('red')])
liststore.append([1,'green',colormap.alloc_color('green')])
iter = liststore.insert(1, (2,'blue',colormap.alloc_color('blue')) )
iter = liststore.insert_after(iter, [3,'yellow',colormap.alloc_color('blue')])
...
</pre></td></tr></table></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-AddingTreeStoreRows"></a>14.2.4.2. Adding Rows to a TreeStore</h4></div></div><div></div></div><p>Adding a row to a <tt class="classname">TreeStore</tt> is similar to
adding a row to a <tt class="classname">ListStore</tt> except that you also have
to specify a parent row (using a <tt class="classname">TreeIter</tt>) to add the
new row to. The <tt class="classname">TreeStore</tt> methods are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
iter = append(<b class="parameter"><tt>parent</tt></b>, <b class="parameter"><tt>row</tt></b>=None)
iter = prepend(<b class="parameter"><tt>parent</tt></b>, <b class="parameter"><tt>row</tt></b>=None)
iter = insert(<b class="parameter"><tt>parent</tt></b>, <b class="parameter"><tt>position</tt></b>, <b class="parameter"><tt>row</tt></b>=None)
iter = insert_before(<b class="parameter"><tt>parent</tt></b>, <b class="parameter"><tt>sibling</tt></b>, <b class="parameter"><tt>row</tt></b>=None)
iter = insert_after(<b class="parameter"><tt>parent</tt></b>, <b class="parameter"><tt>sibling</tt></b>, <b class="parameter"><tt>row</tt></b>=None)
</pre></td></tr></table><p>If <i class="parameter"><tt>parent</tt></i> is <tt class="literal">None</tt>, the
row will be added to the top level rows.</p><p>Each of these methods inserts a row at an implied or specified
position in the <tt class="classname">TreeStore</tt>. The
<tt class="methodname">append</tt>() and <tt class="methodname">prepend</tt>()
methods use implied positions: after the last child row and before the first
child row, respectively. The <tt class="methodname">insert</tt>() method takes
an integer (the parameter <i class="parameter"><tt>position</tt></i>) that specifies
the location where the child row will be inserted. The other two methods
take a <tt class="classname">TreeIter</tt> (<i class="parameter"><tt>sibling</tt></i>) that
references a child row in the <tt class="classname">TreeStore</tt> to insert the
row before or after.</p><p>The <i class="parameter"><tt>row</tt></i> parameter specifies the data that
should be inserted in the row after it is created. If
<i class="parameter"><tt>row</tt></i> is <tt class="literal">None</tt> or not specified, an
empty row will be created. If <i class="parameter"><tt>row</tt></i> is specified it
must be a tuple or list containing as many items as the number of columns in
the <tt class="classname">TreeStore</tt>. The items must also match the data
type of their respective <tt class="classname">TreeStore</tt> columns.</p><p>All methods return a <tt class="classname">TreeIter</tt> that points
at the newly inserted row. The following code fragment illustrates the
creation of a <tt class="classname">TreeStore</tt> and the addition of data rows
to it:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
...
folderpb = gtk.gdk.pixbuf_from_file('folder.xpm')
filepb = gtk.gdk.pixbuf_from_file('file.xpm')
treestore = gtk.TreeStore(int, str, gtk.gdk.Pixbuf)
iter0 = treestore.append(None, [1,'(0,)',folderpb] )
treestore.insert(iter0, 0, [11,'(0,0)',filepb])
treestore.append(iter0, [12,'(0,1)',filepb])
iter1 = treestore.insert_after(None, iter0, [2,'(1,)',folderpb])
treestore.insert(iter1, 0, [22,'(1,1)',filepb])
treestore.prepend(iter1, [21,'(1,0)',filepb])
...
</pre></td></tr></table></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-LargeDataStores"></a>14.2.4.3. Large Data Stores</h4></div></div><div></div></div><p>When a <tt class="classname">ListStore</tt> or
<tt class="classname">TreeStore</tt> contains a large number of data rows,
adding new rows can become very slow. There are a few things that you can do
to mitigate this problem:</p><div class="itemizedlist"><ul type="disc"><li>If adding a large number of rows disconnect the
<tt class="classname">TreeModel</tt> from its <tt class="classname">TreeView</tt>
(using the <tt class="methodname">set_model</tt>() method with the
<i class="parameter"><tt>model</tt></i> parameter set to <tt class="literal">None</tt>) to
avoid <tt class="classname">TreeView</tt> updates for each row
entered.</li><li>Likewise, disable sorting (using the
<tt class="methodname">set_default_sort_func</tt>() method with the
<i class="parameter"><tt>sort_func</tt></i> set to <tt class="literal">None</tt>) while
adding a large number of rows.</li><li>Limit the number of
<tt class="classname">TreeRowReference</tt>s in use since they update their path
with each addition or removal.</li><li>Set the <tt class="classname">TreeView</tt>
"fixed-height-mode" property to <tt class="literal">TRUE</tt> making all rows have
the same height and avoiding the individual calculation of the height of
each row. Only available in PyGTK 2.4 and above.</li></ul></div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-RemovingStoreRows"></a>14.2.5. Removing Rows</h3></div></div><div></div></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-RemovingListStoreRows"></a>14.2.5.1. Removing Rows From a ListStore</h4></div></div><div></div></div><p>You can remove a data row from a
<tt class="classname">ListStore</tt> by using the
<tt class="methodname">remove</tt>() method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
treeiter = liststore.remove(<b class="parameter"><tt>iter</tt></b>)
</pre></td></tr></table><p>where <i class="parameter"><tt>iter</tt></i> is a
<tt class="classname">TreeIter</tt> pointing at the row to remove. The returned
<tt class="classname">TreeIter</tt> (<i class="parameter"><tt>treeiter</tt></i>) points at
the next row or is invalid if <i class="parameter"><tt>iter</tt></i> was pointing at
the last row.</p><p>The <tt class="methodname">clear</tt>() method removes all rows
from the <tt class="classname">ListStore</tt>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
liststore.clear()
</pre></td></tr></table></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-RemovingTreeStoreRows"></a>14.2.5.2. Removing Rows From a TreeStore</h4></div></div><div></div></div><p>The methods for removing data rows from a
<tt class="classname">TreeStore</tt> are similar to the
<tt class="classname">ListStore</tt> methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
result = treestore.remove(<b class="parameter"><tt>iter</tt></b>)
treestore.clear()
</pre></td></tr></table><p>where <i class="parameter"><tt>result</tt></i> is <tt class="literal">TRUE</tt>
if the row was removed and <i class="parameter"><tt>iter</tt></i> points at the next
valid row. Otherwise, <i class="parameter"><tt>result</tt></i> is
<tt class="literal">FALSE</tt> and <i class="parameter"><tt>iter</tt></i> is
invalidated.</p></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-ManagingRowData"></a>14.2.6. Managing Row Data</h3></div></div><div></div></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-AccessingDataValues"></a>14.2.6.1. Setting and Retrieving Data Values</h4></div></div><div></div></div><p>The methods for accessing the data values in a
<tt class="classname">ListStore</tt> and <tt class="classname">TreeStore</tt> have
the same format. All store data manipulations use a
<tt class="classname">TreeIter</tt> to specify the row that you are working
with. Once you have a <tt class="classname">TreeIter</tt> it can be used to
retrieve the values of a row column using the
<tt class="methodname">get_value</tt>() method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
value = store.get_value(<b class="parameter"><tt>iter</tt></b>, <b class="parameter"><tt>column</tt></b>)
</pre></td></tr></table><p>where <i class="parameter"><tt>iter</tt></i> is a
<tt class="classname">TreeIter</tt> pointing at a row,
<i class="parameter"><tt>column</tt></i> is a column number in
<i class="parameter"><tt>store</tt></i>, and, <i class="parameter"><tt>value</tt></i> is the value
stored at the row-column location.</p><p>If you want to retrieve the values from multiple columns in
one call use the <tt class="methodname">get</tt>() method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
values = store.get(iter, column, ...)
</pre></td></tr></table><p>where <i class="parameter"><tt>iter</tt></i> is a
<tt class="classname">TreeIter</tt> pointing at a row,
<i class="parameter"><tt>column</tt></i> is a column number in
<i class="parameter"><tt>store</tt></i>, and, <i class="parameter"><tt>...</tt></i> represents
zero or more additional column numbers and <i class="parameter"><tt>values</tt></i> is
a tuple containing the retrieved data values. For example to retrieve the
values in columns 0 and 2:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
val0, val2 = store.get(iter, 0, 2)
</pre></td></tr></table><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>The <tt class="methodname">get</tt>() method is only available
in PyGTK 2.4 and above.</p></div><p>Setting a single column value is effected using the
<tt class="methodname">set_value</tt>() method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
store.set_value(<b class="parameter"><tt>iter</tt></b>, <b class="parameter"><tt>column</tt></b>, <b class="parameter"><tt>value</tt></b>)
</pre></td></tr></table><p>where <i class="parameter"><tt>iter</tt></i> (a
<tt class="classname">TreeIter</tt>) and <i class="parameter"><tt>column</tt></i> (an int)
specify the row-column location in <i class="parameter"><tt>store</tt></i> and
<i class="parameter"><tt>column</tt></i> is the column number where
<i class="parameter"><tt>value</tt></i> is to be set. <i class="parameter"><tt>value</tt></i> must
be the same data type as the <i class="parameter"><tt>store</tt></i> column.</p><p>If you wish to set the value of more than one column in a row
at a time, use the <tt class="methodname">set</tt>() method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
store.set(<i class="parameter"><tt>iter</tt></i>, <i class="parameter"><tt>...</tt></i>)
</pre></td></tr></table><p>where <i class="parameter"><tt>iter</tt></i> specifies the store row and
<i class="parameter"><tt>...</tt></i> is one or more column number - value pairs
indicating the column and and value to set. For example, the following
call:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
store.set(iter, 0, 'Foo', 5, 'Bar', 1, 123)
</pre></td></tr></table><p>sets the first column to 'Foo', the sixth column to 'Bar' and
the second column to 123 in the <i class="parameter"><tt>store</tt></i> row specified
by <i class="parameter"><tt>iter</tt></i>.</p></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-RearrangingListStoreRows"></a>14.2.6.2. Rearranging ListStore Rows</h4></div></div><div></div></div><p>Individual <tt class="classname">ListStore</tt> rows can be moved
using one of the following methods that are available in PyGTK 2.2 and
above:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
liststore.swap(<b class="parameter"><tt>a</tt></b>, <b class="parameter"><tt>b</tt></b>)
liststore.move_after(<b class="parameter"><tt>iter</tt></b>, <b class="parameter"><tt>position</tt></b>)
liststore.move_before(<b class="parameter"><tt>iter</tt></b>, <b class="parameter"><tt>position</tt></b>)
</pre></td></tr></table><p><tt class="methodname">swap</tt>() swaps the locations of the rows
referenced by the <tt class="classname">TreeIter</tt>s <i class="parameter"><tt>a</tt></i>
and <i class="parameter"><tt>b</tt></i>. <tt class="methodname">move_after</tt>() and
<tt class="methodname">move_before</tt>() move the row referenced by the
<tt class="classname">TreeIter</tt> <i class="parameter"><tt>iter</tt></i> after or before
the row referenced by the <tt class="classname">TreeIter</tt>
<i class="parameter"><tt>position</tt></i>. If <i class="parameter"><tt>position</tt></i> is
<tt class="literal">None</tt>, <tt class="methodname">move_after</tt>() will place
the row at the beginning of the store while
<tt class="methodname">move_before</tt>(), at the end of the store.</p><p>If you want to completely rearrange the
<tt class="classname">ListStore</tt> data rows, use the following method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
liststore.reorder(<i class="parameter"><tt>new_order</tt></i>)
</pre></td></tr></table><p>where <i class="parameter"><tt>new_order</tt></i> is a list of integers
that specify the new row order as:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
<i class="parameter"><tt>new_order</tt></i>[newpos] = oldpos
</pre></td></tr></table><p>For example, if <i class="parameter"><tt>liststore</tt></i> contained
four rows:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
'one'
'two'
'three'
'four'
</pre></td></tr></table><p>The method call:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
liststore.reorder([2, 1, 3, 0])
</pre></td></tr></table><p>would produce the resulting order:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
'three'
'two'
'four'
'one'
</pre></td></tr></table><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>These methods will only rearrange unsorted
<tt class="classname">ListStore</tt>s.</p></div><p>If you want to rearrange rows in PyGTK 2.0 you have to remove
and insert rows using the methods described in <a href="sec-TreeModelInterface.html#sec-AddingStoreRows" title="14.2.4. Adding Rows">Section 14.2.4, “Adding Rows”</a> and <a href="sec-TreeModelInterface.html#sec-RemovingStoreRows" title="14.2.5. Removing Rows">Section 14.2.5, “Removing Rows”</a>.</p></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-RearrangingTreeStoreRows"></a>14.2.6.3. Rearranging TreeStore Rows</h4></div></div><div></div></div><p>The methods used to rearrange <tt class="classname">TreeStore</tt>
rows are similar to the <tt class="classname">ListStore</tt> methods except they
only affect the child rows of an implied parent row - it is not possible to,
say, swap rows with different parent rows.:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
treestore.swap(<b class="parameter"><tt>a</tt></b>, <b class="parameter"><tt>b</tt></b>)
treestore.move_after(<b class="parameter"><tt>iter</tt></b>, <b class="parameter"><tt>position</tt></b>)
treestore.move_before(<b class="parameter"><tt>iter</tt></b>, <b class="parameter"><tt>position</tt></b>)
</pre></td></tr></table><p><tt class="methodname">swap</tt>() swaps the locations of the child
rows referenced by the TreeIters <i class="parameter"><tt>a</tt></i> and
<i class="parameter"><tt>b</tt></i>. <i class="parameter"><tt>a</tt></i> and
<i class="parameter"><tt>b</tt></i> must both have the same parent
row. <tt class="methodname">move_after</tt>() and
<tt class="methodname">move_before</tt>() move the row referenced by the
<tt class="classname">TreeIter</tt> <i class="parameter"><tt>iter</tt></i> after or before
the row referenced by the <tt class="classname">TreeIter</tt>
<i class="parameter"><tt>position</tt></i>. <i class="parameter"><tt>iter</tt></i> and
<i class="parameter"><tt>position</tt></i> must both have the same parent row. If
<i class="parameter"><tt>position</tt></i> is <tt class="literal">None</tt>,
<tt class="methodname">move_after</tt>() will place the row at the beginning of
the store while <tt class="methodname">move_before</tt>(), at the end of the
store.</p><p>The <tt class="methodname">reorder</tt>() method requires an
additional parameter specifying the parent row whose child rows will be
reordered:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
treestore.reorder(<b class="parameter"><tt>parent</tt></b>, <b class="parameter"><tt>new_order</tt></b>)
</pre></td></tr></table><p>where <i class="parameter"><tt>new_order</tt></i> is a list of integers
that specify the new child row order of the parent row specified by the
<tt class="classname">TreeIter</tt> <i class="parameter"><tt>parent</tt></i> as:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
<i class="parameter"><tt>new_order</tt></i>[newpos] = oldpos
</pre></td></tr></table><p>For example, if <i class="parameter"><tt>treestore</tt></i> contained
four rows:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
'parent'
'one'
'two'
'three'
'four'
</pre></td></tr></table><p>The method call:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
treestore.reorder(parent, [2, 1, 3, 0])
</pre></td></tr></table><p>would produce the resulting order:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
'parent'
'three'
'two'
'four'
'one'
</pre></td></tr></table><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>These methods will only rearrange unsorted
<tt class="classname">TreeStore</tt>s.</p></div></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-ManagingMultipleRows"></a>14.2.6.4. Managing Multiple Rows</h4></div></div><div></div></div><p>One of the trickier aspects of dealing with
<tt class="classname">ListStore</tt>s and <tt class="classname">TreeStore</tt>s is
the operation on multiple rows, e.g. moving multiple rows, say, from one
parent row to another or removing rows based on certain criteria. The
difficulty arises from the need to use a <tt class="classname">TreeIter</tt>
that may become invalid as the result of the operation. For
<tt class="classname">ListStore</tt>s and <tt class="classname">TreeStore</tt>s the
TreeIters are persistent as can be checked by using the
<tt class="methodname">get_flags</tt>() method and testing for the
<tt class="literal">gtk.TREE_MODEL_ITERS_PERSIST</tt> flag. However the stackable
<tt class="classname">TreeModelFilter</tt> and
<tt class="classname">TreeModelSort</tt> classes do not have persistent
<tt class="classname">TreeIter</tt>s.</p><p>Assuming that <tt class="classname">TreeIter</tt>s don't persist how
do we move all the child rows from one parent row to another? We have
to:</p><div class="itemizedlist"><ul type="disc"><li>iterate over the parent's children</li><li>retrieve each row's data</li><li>remove each child row</li><li>insert a new row with the old row data in the new
parent's list</li></ul></div><p>We can't rely on the <tt class="methodname">remove</tt>() method to
return a valid <tt class="classname">TreeIter</tt> so we'll just ask for the
first child iter until it returns <tt class="literal">None</tt>. A possible
function to move child rows is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
def move_child_rows(treestore, from_parent, to_parent):
n_columns = treestore.get_n_columns()
iter = treestore.iter_children(from_parent)
while iter:
values = treestore.get(iter, *range(n_columns))
treestore.remove(iter)
treestore.append(to_parent, values)
iter = treestore.iter_children(from_parent)
return
</pre></td></tr></table><p>The above function covers the simple case of moving all child
rows of a single parent row but what if you want to remove all rows in the
<tt class="classname">TreeStore</tt> based on some match criteria, say the first
column value? Here you might think that you could use the
<tt class="methodname">foreach</tt>() method to iterate over all the rows and
remove the matching ones:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
store.foreach(<i class="parameter"><tt>func</tt></i>, <i class="parameter"><tt>user_data</tt></i>)
</pre></td></tr></table><p>where <i class="parameter"><tt>func</tt></i> is a function that is
invoked for each store row and has the signature:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
def func(<i class="parameter"><tt>model</tt></i>, <i class="parameter"><tt>path</tt></i>, <i class="parameter"><tt>iter</tt></i>, <i class="parameter"><tt>user_data</tt></i>):
</pre></td></tr></table><p>where <i class="parameter"><tt>model</tt></i> is the
<tt class="classname">TreeModel</tt> data store, <i class="parameter"><tt>path</tt></i> is
the tree path of a row in <i class="parameter"><tt>model</tt></i>,
<i class="parameter"><tt>iter</tt></i> is a <tt class="classname">TreeIter</tt> pointing at
<i class="parameter"><tt>path</tt></i> and <i class="parameter"><tt>user_data</tt></i> is the
passed in data. if <i class="parameter"><tt>func</tt></i> returns
<tt class="literal">TRUE</tt> the <tt class="methodname">foreach</tt>() method will
cease iterating and return.</p><p>The problem with that is that changing the contents of the store
while the <tt class="methodname">foreach</tt>() method is iterating over it may
have unpredictable results. Using the <tt class="methodname">foreach</tt>()
method to create and save TreeRowReferences to the rows to be removed and
then removing them after the <tt class="methodname">foreach</tt>() method
completes would be a good strategy except that it doesn't work for PyGTK 2.0
and 2.2 where <tt class="classname">TreeRowReference</tt>s are not
available.</p><p>A reliable strategy that covers all the PyGTK variants is to
use the <tt class="methodname">foreach</tt>() method to gather the tree paths
of rows to be removed and then remove them in reverse order to preserve the
validity of the tree paths. An example code fragment utilizing this
strategy is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
...
# match if the value in the first column is >= the passed in value
# data is a tuple containing the match value and a list to save paths
def match_value_cb(model, path, iter, data):
if model.get_value(iter, 0) >= data[0]:
data[1].append(path)
return False # keep the foreach going
pathlist = []
treestore.foreach(match_value_cb, (10, pathlist))
# foreach works in a depth first fashion
pathlist.reverse()
for path in pathlist:
treestore.remove(treestore.get_iter(path))
...
</pre></td></tr></table><p>If you want to search a <tt class="classname">TreeStore</tt> for the
first row that matches some criteria, you probably want to do the iteration
yourself using something like:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
treestore = TreeStore(str)
...
def match_func(model, iter, data):
column, key = data # data is a tuple containing column number, key
value = model.get_value(iter, column)
return value == key
def search(model, iter, func, data):
while iter:
if func(model, iter, data):
return iter
result = search(model, model.iter_children(iter), func, data)
if result: return result
iter = model.iter_next(iter)
return None
...
match_iter = search(treestore, treestore.iter_children(None),
match_func, (0, 'foo'))
</pre></td></tr></table><p>The <tt class="function">search</tt>() function iterates recursively
over the row (specified by <i class="parameter"><tt>iter</tt></i>) and its siblings and
their child rows in a depth first fashion looking for a row that has a
column matching the given key string. The search terminates when a row is
found.</p></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-PythonProtocolSupport"></a>14.2.7. Python Protocol Support</h3></div></div><div></div></div><p>The classes that implement the <tt class="classname">TreeModel</tt>
interface (<tt class="classname">TreeStore</tt> and
<tt class="classname">ListStore</tt> and in PyGTK 2.4, also the
<tt class="classname">TreeModelSort</tt> and
<tt class="classname">TreeModelFilter</tt>) support the Python mapping and
iterator protocols. The iterator protocol allows you to use the Python
<tt class="function">iter</tt>() function on a <tt class="classname">TreeModel</tt>
to create an iterator to be used to iterate over the top level rows in the
<tt class="classname">TreeModel</tt>. A more useful capability is to iterate
using the <tt class="literal">for</tt> statement or a list comprehension. For
example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
...
liststore = gtk.ListStore(str, str)
...
# add some rows to liststore
...
# for looping
for row in liststore:
# do individual row processing
...
# list comprehension returning a list of values in the first column
values = [ r[0] for r in liststore ]
...
</pre></td></tr></table><p>Other parts of the mapping protocols that are supported are using
<tt class="literal">del</tt> to delete a row in the model and extracting a PyGTK
<tt class="classname">TreeModelRow</tt> from the model using a key value that is
a tree path or <tt class="classname">TreeIter</tt>. For example, the following
statements all return the first row in a <tt class="classname">TreeModel</tt>
and the final statement deletes the first child row of the first row:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
row = model[0]
row = model['0']
row = model["0"]
row = model[(0,)]
i = model.get_iter(0)
row = model[i]
del model[(0,0)]
</pre></td></tr></table><p>In addition, you can set the values in an existing row similar
to the following:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
...
liststore = gtk.ListStore(str, int, object)
...
liststore[0] = ['Button', 23, gtk.Button('Label')]
</pre></td></tr></table><p>A PyGTK <tt class="classname">TreeModelRow</tt> object supports the
Python sequence and iterator protocols. You can get an iterator to iterate
over the column values in the row or use the for statement or list
comprehension as well. A <tt class="classname">TreeModelRow</tt> uses the column
number as the index to extract a value. For example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
...
liststore = gtk.ListStore(str, int)
liststore.append(['Random string', 514])
...
row = liststore[0]
value1 = row[1]
value0 = liststore['0'][0]
for value in row:
print value
val0, val1 = row
...
</pre></td></tr></table><p>Using the example from the previous section to iterate over a
<tt class="classname">TreeStore</tt> to locate a row containing a particular
value, the code becomes:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
treestore = TreeStore(str)
...
def match_func(row, data):
column, key = data # data is a tuple containing column number, key
return row[column] == key
...
def search(rows, func, data):
if not rows: return None
for row in rows:
if func(row, data):
return row
result = search(row.iterchildren(), func, data)
if result: return result
return None
...
match_row = search(treestore, match_func, (0, 'foo'))
</pre></td></tr></table><p>You can also set a value in an existing column using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
treestore[(1,0,1)][1] = 'abc'
</pre></td></tr></table><p>The <tt class="classname">TreeModelRow</tt> also supports the
<tt class="literal">del</tt> statement and conversion to lists and tuples using
the Python <tt class="function">list</tt>() and <tt class="function">tuple</tt>()
functions. As illustrated in the above example the
<tt class="classname">TreeModelRow</tt> has the
<tt class="methodname">iterchildren</tt>() method that returns an iterator for
iterating over the child rows of the
<tt class="classname">TreeModelRow</tt>.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-TreeModelSignals"></a>14.2.8. TreeModel Signals</h3></div></div><div></div></div><p>Your application can track changes in a
<tt class="classname">TreeModel</tt> by connecting to the signals that are
emitted by the <tt class="classname">TreeModel</tt>: "row-changed",
"row-deleted", "row-inserted", "row-has-child-toggled" and
"rows-reordered". These signals are used by a
<tt class="classname">TreeView</tt> to track changes in its
<tt class="classname">TreeModel</tt>.</p><p>If you connect to these signals in your application, you may see
clusters of signals when some methods are called. For example the call to
add the first child row to a parent row:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
treestore.append(parent, ['qwe', 'asd', 123])
</pre></td></tr></table><p>will cause the following signal emissions:</p><div class="itemizedlist"><ul type="disc"><li>"row-inserted" where the inserted row will be
empty.</li><li>"row-has-child-toggled" since
<i class="parameter"><tt>parent</tt></i> didn't previously have any child
rows.</li><li>"row-changed" for the inserted row when setting the value
'qwe' in the first column.</li><li>"row-changed" for the inserted row when setting the value
'asd in the second column.</li><li>"row-changed" for the inserted row when setting the value
123 in the third column.</li></ul></div><p>Note that you can't retrieve the row order in the
"rows-reordered" callback since the new row order is passed as an opaque
pointer to an array of integers.</p><p>See the <a href="http://www.pygtk.org/pygtk2reference/class-gtktreemodel.html" target="_top">PyGTK
Reference Manual</a> for more information on the
<tt class="classname">TreeModel</tt> signals.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-SortingTreeModelRows"></a>14.2.9. Sorting TreeModel Rows</h3></div></div><div></div></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-TreeSortable"></a>14.2.9.1. The TreeSortable Interface</h4></div></div><div></div></div><p>The <tt class="classname">ListStore</tt> and
<tt class="classname">TreeStore</tt> objects implement the
<tt class="classname">TreeSortable</tt> interface that provides methods for
controlling the sorting of <tt class="classname">TreeModel</tt> rows. The key
element of the interface is a "sort column ID" which is an arbitrary integer
value referring to a sort comparison function and associated user data. A
sort column ID must be greater than or equal to zero. A sort column ID is
created by using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
treesortable.set_sort_func(<i class="parameter"><tt>sort_column_id</tt></i>, <i class="parameter"><tt>sort_func</tt></i>, <i class="parameter"><tt>user_data</tt></i>=<tt class="literal">None</tt>)
</pre></td></tr></table><p>where <i class="parameter"><tt>sort_column_id</tt></i> is a programmer
assigned integer value, <i class="parameter"><tt>sort_func</tt></i> is a function or
method used to compare rows and <i class="parameter"><tt>user_data</tt></i> is context
data. <i class="parameter"><tt>sort_func</tt></i> has the signature:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
def sort_func_function(model, iter1, iter2, data)
def sort_func_method(self, model, iter1, iter2, data)
</pre></td></tr></table><p>where <i class="parameter"><tt>model</tt></i> is the
<tt class="classname">TreeModel</tt> containing the rows pointed to by the
<tt class="classname">TreeIter</tt>s <i class="parameter"><tt>iter1</tt></i> and
<i class="parameter"><tt>iter2</tt></i> and <i class="parameter"><tt>data</tt></i> is
<i class="parameter"><tt>user_data</tt></i>. <i class="parameter"><tt>sort_func</tt></i> should
return: -1 if the <i class="parameter"><tt>iter1</tt></i> row should precede the
<i class="parameter"><tt>iter2</tt></i> row; 0, if the rows are equal; and, 1 if the
<i class="parameter"><tt>iter2</tt></i> row should precede the
<i class="parameter"><tt>iter1</tt></i> row. The sort comparison function should always
assume that the sort order is <tt class="literal">gtk.SORT_ASCENDING</tt> as the
sort order will be taken into account by the
<tt class="classname">TreeSortable</tt> implementations.</p><p>The same sort comparison function can be used for multiple sort
column IDs by varying the user_data to provide context information. For
example, the <i class="parameter"><tt>user_data</tt></i> specified in the
<tt class="methodname">set_sort_func</tt>() method could be the index of the
column to extract the sort data from.</p><p>Once a sort column ID is created a store can use it for sorting
by calling the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
treesortable.set_sort_column_id(<b class="parameter"><tt>sort_column_id</tt></b>, <b class="parameter"><tt>order</tt></b>)
</pre></td></tr></table><p>where <i class="parameter"><tt>order</tt></i> is the sort order either
<tt class="literal">gtk.SORT_ASCENDING</tt> or
<tt class="literal">gtk.SORT_DESCENDING</tt>.</p><p>The sort column ID of -1 means that the store should use the
default sort function that is set using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
treesortable.set_default_sort_func(<i class="parameter"><tt>sort_func</tt></i>, <i class="parameter"><tt>user_data</tt></i>=<tt class="literal">None</tt>)
</pre></td></tr></table><p>You can check if a store has a default sort function using the
method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
result = treesortable.has_default_sort_func()
</pre></td></tr></table><p>which returns <tt class="literal">TRUE</tt> if a default sort function
has been set.</p><p>Once a sort column ID has been set on a
<tt class="classname">TreeModel</tt> implementing the
<tt class="classname">TreeSortable</tt> interface it cannot be returned to the
original unsorted state. You can change the sort function or use a default
sort function but you cannot set the <tt class="classname">TreeModel</tt> to
have no sort function.</p></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-SortingStores"></a>14.2.9.2. Sorting in ListStores and TreeStores</h4></div></div><div></div></div><p>When a <tt class="classname">ListStore</tt> or
<tt class="classname">TreeStore</tt> object is created it automatically sets up
sort column IDs corresponding to the columns in the store using the column
index number. For example, a <tt class="classname">ListStore</tt> with three
columns would have three sort column IDs (0, 1, 2) setup
automatically. These sort column IDs are associated with an internal sort
comparison function that handles the fundamental types:</p><div class="itemizedlist"><ul type="disc"><li>'gboolean'</li><li>str</li><li>int</li><li>long</li><li>float</li></ul></div><p>Initially a <tt class="classname">ListStore</tt> or
<tt class="classname">TreeStore</tt> is set with a sort column ID of -2 that
indicates that no sort function is being used and that the store is
unsorted. Once you set a sort column ID on a
<tt class="classname">ListStore</tt> or <tt class="classname">TreeStore</tt> you
cannot set it back to -2.</p><p>If you want to maintain the default sort column IDs you can set up
a sort column ID well out of the range of the number of columns such as 1000
and up. Then you can switch between the default sort function and your
application sort functions as needed.</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-TreeViewWidget.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-TreeViewWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-TreeViews.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 14. Tree View Widget </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 14.3. TreeViews</td></tr></table></div></body></html>
|