self.wine = wine
self.winery = winery
self.grape = grape
self.year = year
很简单, 下一步我们需要创建一个给wineDlg使用的类, 我们称它为wineDialog:
class wineDialog:
"""This class is used to show wineDlg"""
#setup the glade file
self.gladefile = "pywine.glade"
#setup the wine that we will return
self.wine = Wine(wine,winery,grape,year)
下一步我们需要为wineDialog添加一个函数, 它来从glade文件中装载wineDialg物件并显示. 我们还想要返回这个对话框的执行结果, 这会是一个gtk_RESPONSE, 你可以从 PyGTK的网站上
得到更多的信息.
这个就是run 函数:
def run(self):
"""This function will show the wineDlg"""
#load the dialog from the glade file
self.wTree = gtk.glade.XML(self.gladefile, "wineDlg")
#Get the actual dialog widget
self.dlg = self.wTree.get_widget("wineDlg")
#Get all of the Entry Widgets and set their text
self.enWine = self.wTree.get_widget("enWine")
self.enWine.set_text(self.wine.wine)
self.enWinery = self.wTree.get_widget("enWinery")
self.enWinery.set_text(self.wine.winery)
self.enGrape = self.wTree.get_widget("enGrape")
self.enGrape.set_text(self.wine.grape)
self.enYear = self.wTree.get_widget("enYear")
self.enYear.set_text(self.wine.year)
#run the dialog and store the response
self.result = self.dlg.run()
#get the value of the entry fields
self.wine.wine = self.enWine.get_text()
self.wine.winery = self.enWinery.get_text()
self.wine.grape = self.enGrape.get_text()
self.wine.year = self.enYear.get_text()
#we are done with the dialog, destroy it
self.dlg.destroy()
#return the result and the wine
return self.result,self.wine
你会注意到我们装载对话框的方法用的是和装载主窗口一样的方法. 我们调用gtk_glade_XML()并把我们想要装载物件的名称传给它. 这将会自动的显示这个对话框(和装载主窗口的行为相同), 但这样不够好, 我们想让run函数等待用户退出了这个对话框才返回. 要这么做我们需要从物件树里得到这个这个对话框物件(self.dlg = self.wTree.get_widget(“wineDlg”)),然后调用 GTKDialogs 的run函数
. 下面是PyGTK文档对这个函数的描述:
Run()方法会在一个无穷的主循环里阻塞到它收到一个”response”信号或是销毁. 如果这个对话框是被销毁了, run ()方法会返回一个gtk_RESPONSE_NONE; 否则它返回一个在response信号中的响应id. 在进入这个无穷的主循环之前run ()方法会为你调用对话框的gtk_Widget_show()函数. 注意你仍然需要自己负责显示对话框的子窗口.
在run()方法运行期间, delete事件的默认行为是被禁止的, 如果对话框收到一个delete的事件, 它并不会像窗口通常那样进行销毁, 这时run()方法会返回一个gtk_RESPONSE_DELETE_EVENT. 而且在run ()方法运行的时候对话框是模态的. 你可以通过调用responese()函数产生一个response信号来强制run ()方法在任何时候退出. 在run()方法运行的时候销毁对话框是很糟糕的主意, 因为你后面的代码无法知道对话框是不是已经销毁了.
在run()方法返回后, 你需要负责对话框的隐藏和销毁.
Ok按钮会返回gtk_RESPONSE_OK, Cancel按钮会返回gtk_RESPONSE_CANCEL, 大部分情况下我们仅关心对话框返回的wine信息是不是由用户点Ok按钮产生的.
你还可以看到我们从对话框里得到GTKEntry物件来取/设置它们的文字. 总得来说这个函数还是相当简单的.
树状视图和列表存储(List Stores)
现在我们有了用户想要往列表中添加的酒, 我们需要把它添加进 gtk_TreeView
中.
GTKTreeViews的主要特性就是它们按照模型指定的任何方式来显示它们的数据. 数据模型可以用 gtk_ListStore
, gtk_TreeStore
, gtk_TreeModelSort
,或是 gtk_GenericTreeModel
. 在本例子中我们将使用 gkt_ListStore.
树状视图与模型的关系有些复杂,但是一旦你可以使用它你就会理解为什么它们是这样的. 很简单的讲模型表现数据,而树状视图则是一个简单的显示数据的方法. 所以对于同一份数据(模型)你可以有多个完全不同的视图. 下面是 GTK+参考手册
中的内容:
在GTK+中要创建一个树或列表可以使用结合使用GtkTreeModel接口和GtkTreeView物件. 这个物件使用模型/视图/控制器模式设计, 它由以下四个主要部分组成:
树状视图物件(GtkTreeView)
列视图 (GtkTreeViewcolumn)
单元渲染器(GtkCellRenderer等等)
模型接口(GtkTreeModel)
视图是由前面的三组对象组成, 最后一个是模型. MVC设计模式的一个主要收益是可以使用单个模型创建多个视图. 例如:由文件系统映射的模型(可能由一个文件管理器创建), 可以创建多种视图来显示文件系统的各个部分, 但仅需要在内存中保存一份拷贝
我们要做的第一件是在自动把词典和物件树连接上后往pyWine类的__init__函数中添加一些代码:
#Here are some variables that can be reused later
self.cWine = 0
self.cWinery = 1
self.cGrape = 2
self.cYear = 3
#Get the treeView from the widget Tree
self.wineView = self.wTree.get_widget("wineView")
#Add all of the List Columns to the wineView
self.AddWineListColumn(self.sWine, self.cWine)
self.AddWineListColumn(self.sWinery, self.cWinery)
self.AddWineListColumn(self.sGrape, self.cGrape)
self.AddWineListColumn(self.sYear, self.cYear)
这个代码是相当直观的, 首先我们创建一些类似定义的变量(这样我们在后面就可以很轻松的改变它们)然后我们从物件树中得到gtk_TreeView. 在这之后我们通过调用一个新的函数来往列表中添加我们需要的列. AddWineListColumn是一个很快的小函数,但它能防止我们每次重复写创建列的代码.
def AddWineListColumn(self, title, columnId):
“”"This function adds a column to the list view.
First it create the gtk.TreeViewColumn and then set
some needed properties”"”
column = gtk.TreeViewColumn(title, gtk.CellRendererText()
, text=columnId)
column.set_resizable(True)
column.set_sort_column_id(columnId)
self.wineView.append_column(column)
这个代码有一点点复杂, 首先我们创建一个使用 gtk_CellRendererText
作为它的 gtk_CellRenderer
的新 gtk_TreeViewColumn
. 这里是一些从 GTK+参考手册
里的较全的信息:
一旦GtkTreeView物件有了一个模型, 它需要知道如何显示这个模型. 它通过列和单元渲染器来完成这项工作.
单元渲染器是用来使用某种方法在树状模型中绘图这些数据. 在GTK+2.x中有很多单元渲染器, 包括: GtkCellRenderText, GtkCellRendererPixbuf 和GtkCellRendererToggle. 写一个自定义的渲染器也相对简单.
GtkTreeView使用GtkTreeViewColumn对象来组织在树状视图中纵的列. 它需要知道列的名字用来以标签的形式显示给用户, 使用单元渲染器的类型和对于一个给定的行它需要得到的数据块.
因此简单的讲我们在创建一个包含特定标题的列, 并指明它将会使用gtk_CellRendererText(来显示简单的文字),然后再告诉它它与模型中的哪一项关联在一起.然后我们把它设置成可以改变大小而且用户可以通过点击列的头来对它进行排序. 在这之后我们把这一列加到视图中.
好了, 我们完成了模型的创建. 我们要再回到pyWine类的__init__函数里继续:
#Create the listStore Model to use with the wineView
self.wineList = gtk.ListStore(str, str, str, str)
#Attatch the model to the treeView
self.wineView.set_model(self.wineList)
大体上我们仅仅创建了一个gtk_ListStore并告诉它它有四个子项, 并且它们都是字符串. 然后我们把这个模型与视图绑定起来, 这就是所有我们需要为初始化gtk_TreeView做的.
把所有合并到一起
我们要做的最后一件事是完成pyWine类中的OnAddWine函数(从菜单或工具栏按钮调用). 这个函数很简单:
OnAddWine(self, widget):
"""Called when the use wants to add a wine"""
#Create the dialog, show it, and store the results
wineDlg = wineDialog();
result,newWine = wineDlg.run()
if (result == gtk.RESPONSE_OK):
"""The user clicked Ok, so let's add this
wine to the wine list"""
self.wineList.append(newWine.getList())
这里我们创建了一个wineDialog的实例, 然后运行它并把用户输入的酒的信息保存.然后我们检查result是不是gtk_RESPONSE_OK(用户点击了Ok按钮), 如果是我们就把酒的信息添加到gtk_ListStore中, 它会自动的在gtk_TreeView中显示出来因此它们是连接在一起的.
在wine类中我使用简单的getList函数以使阅读代码变得简单一些:
def getList(self):
"""This function returns a list made up of the
wine information. It is used to add a wine to the
wineList easily"""
return [self.wine, self.winery, self.grape, self.year]
到这里这个简单程序就算完成了, 尽管它不保存任何信息或是任何和它类似的信息, 但是它确实描述了一些创建一个完整pyGTK 应用程序的基本步骤.
完整的代码和Glade文件可以在 这里
下载,你也可心浏览下面的完整程序:
#!/usr/bin/env python
import sys
try:
import pygtk
pygtk.require("2.0")
except:
pass
try:
import gtk
import gtk.glade
except:
sys.exit(1)
class pyWine:
"""This is an Hello World GTK application"""
def __init__(self):
#Get the treeView from the widget Tree
self.wineView = self.wTree.get_widget("wineView")
#Add all of the List Columns to the wineView
self.AddWineListColumn(self.sWine, self.cWine)
self.AddWineListColumn(self.sWinery, self.cWinery)
self.AddWineListColumn(self.sGrape, self.cGrape)
self.AddWineListColumn(self.sYear, self.cYear)
#Create the listStore Model to use with the wineView
self.wineList = gtk.ListStore(str, str, str, str)
#Attache the model to the treeView
self.wineView.set_model(self.wineList)
def AddWineListColumn(self, title, columnId):
"""This function adds a column to the list view.
First it create the gtk.TreeViewColumn and then set
some needed properties"""
def OnAddWine(self, widget):
"""Called when the use wants to add a wine"""
#Cteate the dialog, show it, and store the results
wineDlg = wineDialog();
result,newWine = wineDlg.run()
if (result == gtk.RESPONSE_OK):
"""The user clicked Ok, so let's add this
wine to the wine list"""
self.wineList.append(newWine.getList())
class wineDialog:
"""This class is used to show wineDlg"""
#setup the glade file
self.gladefile = "pywine.glade"
#setup the wine that we will return
self.wine = Wine(wine,winery,grape,year)
def run(self):
"""This function will show the wineDlg"""
#load the dialog from the glade file
self.wTree = gtk.glade.XML(self.gladefile, "wineDlg")
#Get the actual dialog widget
self.dlg = self.wTree.get_widget("wineDlg")
#Get all of the Entry Widgets and set their text
self.enWine = self.wTree.get_widget("enWine")
self.enWine.set_text(self.wine.wine)
self.enWinery = self.wTree.get_widget("enWinery")
self.enWinery.set_text(self.wine.winery)
self.enGrape = self.wTree.get_widget("enGrape")
self.enGrape.set_text(self.wine.grape)
self.enYear = self.wTree.get_widget("enYear")
self.enYear.set_text(self.wine.year)
#run the dialog and store the response
self.result = self.dlg.run()
#get the value of the entry fields
self.wine.wine = self.enWine.get_text()
self.wine.winery = self.enWinery.get_text()
self.wine.grape = self.enGrape.get_text()
self.wine.year = self.enYear.get_text()
#we are done with the dialog, destory it
self.dlg.destroy()
#return the result and the wine
return self.result,self.wine
class Wine:
"""This class represents all the wine information"""
def getList(self):
"""This function returns a list made up of the
wine information. It is used to add a wine to the
wineList easily"""
return [self.wine, self.winery, self.grape, self.year]
if __name__ == "__main__":
wine = pyWine()
gtk.main()