含有章节索引的中文 文章模板

::-- ehu4ever [2005-09-24 03:06:40]

1. Advanced Widgets

Not all widgets are as easy to use as simple Entry Boxes or Spin Buttons. As you've seen with the text view in the previous demo, some widgets require initialization to use. A large part of this initialization requirement is that the widgets themselves are portals into the data set, not the data set itself. For example, you might have multiple text views, each representing different parts of the same text buffer. Classical GUI design text refers to this as the model, view, controller design. It is hoped that you'll need to know as little about that as possible.

Now you're going to add a tree view to the left side of your application, which will contain a server list. The easiest way to do this is to use the Widget Tree (another window you can activate from Glade's View menu). Select the first object under the hbox1, as shown in Figure 13-23, and insert a new container before it. This will add another column to the horizontal box, to the left of the label and button.

Figure 13-23

The Widget Tree is extremely useful for advanced Glade users. As you modify your application, you can cut and paste various widgets from one container to another, or simply add new containers where you want to, without having to dramatically redo the GUI mock-up. Unfortunately, there is currently no Undo feature in Glade so save when you're happy with the current state, and then experiment.

Add a Tree View widget to the newly created slot to the left of the other widgets. Your Glade mock-up will now look like the window shown in Figure 13-24.

Figure 13-24

The new GUI you can see in figure 13-25 will work just as well with your existing PyRAP . py code, but the Tree View widget won't do anything, because there's no initialization code for it and we haven't set up any signals for it

Figure 13-25

Tree Views display data in a columnar format, but as you can see, no columns will show up in your application yet; you need to manually set the column headers. In addition, the figure shows that the author has changed the main window's title to be "pyRAP," in anticipation of adding network support and some application logic to enable two applications to communicate with a central server and have a "rap battle" with each other.

To fill in your Tree View, you'll have to initialize it, much as you did with your text view earlier. Normally, it is wise to split this process off into another file, but in this case, you'll keep it all together. The following code first creates a model variable that contains a TreeStore model. The model variable knows it is going to take two strings as columns. The insert_row function (further below) is a wrapper to the model . insert_after and model . set_value functions. This code is largely cut-and-paste when designing your own projects. An important concept in this code, and in the gtk API in general (and many other APIs), is the concept of an iterator. An iterator is simply an object that holds a position within a list or other data structure. In this case, the insert_row function is returning an iterator that holds the position within the tree model into which a row was inserted. Later, we can pass that iterator back into insert_row to insert a row under the "host" line. The following code fragment also sets the TreeView widget to use the new model we created with the API call set_model. Also notice that we're grabbing the treeview1 widget from wherever it happens to be in the Glade-created GUI. If we move treeview1, this code does not have to change.

Put this code at the end of the init method of your PyRAP class:

                #initialize our host tree
                self.hosttree=self.wTree.get_widget("treeview1") 
                model=gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING) 
                self.hostsmodel=model
                host_inter=insert_row(model,None,'www.immunitysec.com', 'Default Main Server')
                self.hosttree.set_model(model)

In the following code you define a renderer, which you will use to display a line of text inside one of the columns of the TreeView. You then append that column to the TreeView widget. The text=0 is not, as it appears, a Boolean value but rather the index into the model from which the text of the column should come. In this case, insert_row is going to put the hostname (in this case 'www. immunitysec.com') as the first value in a row in the model:

                renderer=gtk.CellRendererText() 
                column=gtk.TreeViewColumn("Host/Channel",renderer, text=0) 
                column.set_resizable(True)
                self.hosttree.append_column(column)

You do this again for a second column, giving it an index into the model of 1 (the second value in the model's row):

                renderer=gtk.CellRendererText()
                column=gtk.TreeViewColumn("Users",renderer, text=1) 
                column.set_resizable(True)
                self.hosttree.append_column(column)

And, of course, you'll need to add the insert_row method:

        def insert_row(self,model,parent,firstcolumn,secondcolumn, thirdcolumn=None): 
                myiter=model.insert_after(parent,None) model.set_value(myiter,0,firstcolumn) 
                model.set_value(myiter,1,secondcolumn) 
                if thirdcolumn != None:
                        model.set_value(myiter,2,thirdcolumn) 
                return myiter

When all of this is inserted into the ini t function of your PyRAP class, and you run your application, you should see your column headers and some initial information in your tree view, as shown in Figure 13-26.

Figure 13-26

Currently, there will only be one pyRAP server, so you can leave that tree view at that. If you want, you can add signal handlers that respond to button presses to generate drop-down menus or perform other actions based on which line in the host tree the user has selected. The following sample code is included to demonstrate how this can be done.

In this sample code, you add a button_press signal to the GUI in Glade and in your code's signal connection dictionary:

        #add this code to your signal dictionary in PyRAP:__init__ to 
        #capture treeview1's button presses 
        "on_treeview1_button_press_event": self.moduletree_press,

        #The handler for the button press looks like this.
        #You can place this directly in your PyRAP class as a method
        def treeview1_press(self,obj,event):
                """
                Handle people double clicking on our tree view
                """
                #print "Clicked"
                if event.type==gtk.gdk._2BUTTON_PRESS:
                        #print "Double Click" 
                        model,iter=self.treeview1.get_selection().get_selected()
                        if iter==None:
                                print "weird - nothing was selected, yet we got a double-click" 
                                return
                        nodetext=model.get_value(iter,0)
                        #now do something based on nodetext.