08 PyGTK 中的高级部件
在教程的这个部分,我们将介绍一些更高级的部件。
IconView
IconView是一个在网格中显示一系列的图标的部件。
Code:iconview.py
#!/usr/bin/python
# ZetCode PyGTK tutorial
#
# This example demonstrates the IconView widget.
# It shows the contents of the currently selected
# directory on the disk.
#
# author: jan bodnar
# website: zetcode.com
# last edited: February 2009
import gtk
import os
COL_PATH = 0
COL_PIXBUF = 1
COL_IS_DIRECTORY = 2
class PyApp(gtk.Window):
def __init__(self):
super(PyApp, self).__init__()
self.set_size_request(650, 400)
self.set_position(gtk.WIN_POS_CENTER)
self.connect("destroy", gtk.main_quit)
self.set_title("IconView")
self.current_directory = '/'
vbox = gtk.VBox(False, 0);
toolbar = gtk.Toolbar()
vbox.pack_start(toolbar, False, False, 0)
self.upButton = gtk.ToolButton(gtk.STOCK_GO_UP);
self.upButton.set_is_important(True)
self.upButton.set_sensitive(False)
toolbar.insert(self.upButton, -1)
homeButton = gtk.ToolButton(gtk.STOCK_HOME)
homeButton.set_is_important(True)
toolbar.insert(homeButton, -1)
self.fileIcon = self.get_icon(gtk.STOCK_FILE)
self.dirIcon = self.get_icon(gtk.STOCK_OPEN)
sw = gtk.ScrolledWindow()
sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
vbox.pack_start(sw, True, True, 0)
self.store = self.create_store()
self.fill_store()
iconView = gtk.IconView(self.store)
iconView.set_selection_mode(gtk.SELECTION_MULTIPLE)
self.upButton.connect("clicked", self.on_up_clicked)
homeButton.connect("clicked", self.on_home_clicked)
iconView.set_text_column(COL_PATH)
iconView.set_pixbuf_column(COL_PIXBUF)
iconView.connect("item-activated", self.on_item_activated)
sw.add(iconView)
iconView.grab_focus()
self.add(vbox)
self.show_all()
def get_icon(self, name):
theme = gtk.icon_theme_get_default()
return theme.load_icon(name, 48, 0)
def create_store(self):
store = gtk.ListStore(str, gtk.gdk.Pixbuf, bool)
store.set_sort_column_id(COL_PATH, gtk.SORT_ASCENDING)
return store
def fill_store(self):
self.store.clear()
if self.current_directory == None:
return
for fl in os.listdir(self.current_directory):
if not fl[0] == '.':
if os.path.isdir(os.path.join(self.current_directory, fl)):
self.store.append([fl, self.dirIcon, True])
else:
self.store.append([fl, self.fileIcon, False])
def on_home_clicked(self, widget):
self.current_directory = os.path.realpath(os.path.expanduser('~'))
self.fill_store()
self.upButton.set_sensitive(True)
def on_item_activated(self, widget, item):
model = widget.get_model()
path = model[item][COL_PATH]
isDir = model[item][COL_IS_DIRECTORY]
if not isDir:
return
self.current_directory = self.current_directory + os.path.sep + path
self.fill_store()
self.upButton.set_sensitive(True)
def on_up_clicked(self, widget):
self.current_directory = os.path.dirname(self.current_directory)
self.fill_store()
sensitive = True
if self.current_directory == "/": sensitive = False
self.upButton.set_sensitive(sensitive)
PyApp()
gtk.main()
这个例子显示了当前选择的目录的图标。它有一个工具栏和两个按钮,up按钮和Home按钮。我们使用它们来操作文件系统。
self.current_directory = '/'
current_directory就是被IconView部件显示的目录。
def create_store(self):
store = gtk.ListStore(str, gtk.gdk.Pixbuf, bool)
store.set_sort_column_id(COL_PATH, gtk.SORT_ASCENDING)
return store
create_store()方法创建了一个ListStore,它是IconView部件中使用的数据模型。它有三个参数,目录名,图标的图像缓存和一个布尔变量,其指示的是我们有一个目录还是一个文件。
f not fl[0] == '.':
if os.path.isdir(os.path.join(self.current_directory, fl)):
self.store.append([fl, self.dirIcon, True])
else:
self.store.append([fl, self.fileIcon, False])
在fill_store()方法中,我们用数据充填了这个ListStore。这里,我们从当前路径中找出了所有的目录,我们排除了以“.”开头的不可见目录。
def on_home_clicked(self, widget):
self.current_directory = os.path.realpath(os.path.expanduser('~'))
self.fill_store()
self.upButton.set_sensitive(True)
如果我们点击Home按钮,那么home目录将会成为当前目录。我们重新充填了这个ListStore,并且使up按钮处于激活状态。
在on_item_activated()方法中,我们和一个事件进行了交互,这个事件就是当我们点击IconView部件中的一个图标的时候产生的。
model = widget.get_model()
path = model[item][COL_PATH]
isDir = model[item][COL_IS_DIRECTORY]
if not isDir:
return
我们得到了被激活项目的路径,并且我们来判断,它是否是一个目录或者一个文件,如果它是一个文件,我们就直接返回。
self.current_directory = self.current_directory + os.path.sep + path
self.fill_store()
self.upButton.set_sensitive(True)
如果他是一个目录,我们就将当前目录替换根目录,并且重新充填ListStore和激活up按钮。
def on_up_clicked(self, widget):
self.current_directory = os.path.dirname(self.current_directory)
self.fill_store()
sensitive = True
if self.current_directory == "/": sensitive = False
self.upButton.set_sensitive(sensitive)
如果我们点击up按钮,我们就用当前目录的上级目录替换它自己,重新充填ListStore,并且如果我们还在文件系统的根目录之下,up按钮会被激活。
ListView
在下面的例子中,我们使用一个TreeView部件来展示一个列表视图(list view),并且ListStore又被用来存储数据。
Code:listview.py
#!/usr/bin/python
# ZetCode PyGTK tutorial
#
# This example shows a TreeView widget
# in a list view mode
#
# author: jan bodnar
# website: zetcode.com
# last edited: February 2009
import gtk
actresses = [('jessica alba', 'pomona', '1981'), ('sigourney weaver', 'new york', '1949'),
('angelina jolie', 'los angeles', '1975'), ('natalie portman', 'jerusalem', '1981'),
('rachel weiss', 'london', '1971'), ('scarlett johansson', 'new york', '1984' )]
class PyApp(gtk.Window):
def __init__(self):
super(PyApp, self).__init__()
self.set_size_request(350, 250)
self.set_position(gtk.WIN_POS_CENTER)
self.connect("destroy", gtk.main_quit)
self.set_title("ListView")
vbox = gtk.VBox(False, 8)
sw = gtk.ScrolledWindow()
sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
vbox.pack_start(sw, True, True, 0)
store = self.create_model()
treeView = gtk.TreeView(store)
treeView.connect("row-activated", self.on_activated)
treeView.set_rules_hint(True)
sw.add(treeView)
self.create_columns(treeView)
self.statusbar = gtk.Statusbar()
vbox.pack_start(self.statusbar, False, False, 0)
self.add(vbox)
self.show_all()
def create_model(self):
store = gtk.ListStore(str, str, str)
for act in actresses:
store.append([act[0], act[1], act[2]])
return store
def create_columns(self, treeView):
rendererText = gtk.CellRendererText()
column = gtk.TreeViewColumn("Name", rendererText, text=0)
column.set_sort_column_id(0)
treeView.append_column(column)
rendererText = gtk.CellRendererText()
column = gtk.TreeViewColumn("Place", rendererText, text=1)
column.set_sort_column_id(1)
treeView.append_column(column)
rendererText = gtk.CellRendererText()
column = gtk.TreeViewColumn("Year", rendererText, text=2)
column.set_sort_column_id(2)
treeView.append_column(column)
def on_activated(self, widget, row, col):
model = widget.get_model()
text = model[row][0] + ", " + model[row][1] + ", " + model[row][2]
self.statusbar.push(0, text)
PyApp()
gtk.main()
在我们的例子中,我们在TreeView部件中显示了有六个女演员的列表。它们中的每一行显示了名字、出生地和出生年份。
def create_model(self):
store = gtk.ListStore(str, str, str)
for act in actresses:
store.append([act[0], act[1], act[2]])
return store
在create_model()方法中,我们创建了ListStore。这个ListStore有三个参数,女演员的名字,出生地和出生年份。这是我们TreeView部件的数据模型。
treeView = gtk.TreeView(store)
treeView.connect("row-activated", self.on_activated)
treeView.set_rules_hint(True)
这里我们创建了一个TreeView部件,将ListStore作为参数。set_rules_hint()方法改变TreeView部件中没两行的背景颜色。
rendererText = gtk.CellRendererText()
column = gtk.TreeViewColumn("Name", rendererText, text=0)
column.set_sort_column_id(0)
treeView.append_column(column)
在create_columns()方法中,我们对我们的TreeView部件增加了三栏。上面的代码创建了一栏来显示女演员的名字。CellRendererText从三个模型中的第一栏中获取它的文本。(默认文本为0)
def on_activated(self, widget, row, col):
model = widget.get_model()
text = model[row][0] + ", " + model[row][1] + ", " + model[row][2]
self.statusbar.push(0, text)
如果我们双击某个项目,我们将在状态栏中显示整行的内容。
Tree
在这章最后的例子中,我们使用TreeView部件来展示一个分层结构的数据树。
Code:tree.py
#!/usr/bin/python
# ZetCode PyGTK tutorial
#
# This example shows a TreeView widget
# in a tree view mode
#
# author: jan bodnar
# website: zetcode.com
# last edited: February 2009
import gtk
class PyApp(gtk.Window):
def __init__(self):
super(PyApp, self).__init__()
self.set_size_request(400, 300)
self.set_position(gtk.WIN_POS_CENTER)
self.connect("destroy", gtk.main_quit)
self.set_title("Tree")
tree = gtk.TreeView()
languages = gtk.TreeViewColumn()
languages.set_title("Programming languages")
cell = gtk.CellRendererText()
languages.pack_start(cell, True)
languages.add_attribute(cell, "text", 0)
treestore = gtk.TreeStore(str)
it = treestore.append(None, ["Scripting languages"])
treestore.append(it, ["Python"])
treestore.append(it, ["PHP"])
treestore.append(it, ["Perl"])
treestore.append(it, ["Ruby"])
it = treestore.append(None, ["Compiling languages"])
treestore.append(it, ["C#"])
treestore.append(it, ["C++"])
treestore.append(it, ["C"])
treestore.append(it, ["Java"])
tree.append_column(languages)
tree.set_model(treestore)
self.add(tree)
self.show_all()
PyApp()
gtk.main()
这次我们使用TreeView部件来展示分层结构的数据。
tree = gtk.TreeView()
TreeView部件被创建。
languages = gtk.TreeViewColumn()
languages.set_title("Programming languages")
它含有一个名为“Programming languages”的一栏。
cell = gtk.CellRendererText()
languages.pack_start(cell, True)
languages.add_attribute(cell, "text", 0)
我们在TreeView部件中展示了文本数据。
treestore = gtk.TreeStore(str)
为了存储数据,我们使用ListStore对象。
it = treestore.append(None, ["Scripting languages"])
treestore.append(it, ["Python"])
treestore.append(it, ["PHP"])
我们追加数据到这个树中。TreeIter对象被用来在行中存取数据。
tree.append_column(languages)
一栏被追加到树中。
tree.set_model(treestore)
最后我们为这个树部件设置一个数据模型。
在教程的这章中,我们讨论了PyGTK中的高级部件。