官方demo中所有的例子程序最后都是在一个gtk-demo.py中展现出来的。本文稍微有做一点修改。就是左侧目录可以展示多级子目录。
例子
先上一张效果图
代码:
#!/usr/bin/env python3
# -*- Mode: Python; py-indent-offset: 4 -*-
# vim: tabstop=4 shiftwidth=4 expandtab
#
# Copyright (C) 2010 Red Hat, Inc., John (J5) Palmieri <johnp@redhat.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
# USA
import codecs
import os
import sys
import textwrap
import glob
import gi
gi.require_version('Pango', '1.0')
gi.require_version('GdkPixbuf', '2.0')
gi.require_version('Gtk', '3.0')
from gi.repository import GLib, GObject, Pango, GdkPixbuf, Gtk, Gio
try:
gi.require_version('GtkSource', '3.0')
from gi.repository import GtkSource # PyFlakes
except Exception:
GtkSource = None
DEMOROOTDIR = os.path.abspath(os.path.dirname(__file__))
DEMOCODEDIR = os.path.join(DEMOROOTDIR, 'demos')
sys.path.insert(0, DEMOROOTDIR)
class Demo(GObject.GObject):
__gtype_name__ = 'GtkDemo'
def __init__(self, title, module, filename):
super(Demo, self).__init__()
self.title = title
self.module = module
self.filename = filename
@classmethod
def new_from_file(cls, path):
relpath = os.path.relpath(path, DEMOROOTDIR)
packagename = os.path.dirname(relpath).replace(os.sep, '.')
modulename = os.path.splitext(os.path.basename(relpath))[0]
try:
package = __import__(packagename, globals(), locals(), [modulename], 0)
module = getattr(package, modulename)
return cls(module.TITLE, module, path)
except AttributeError as e:
raise AttributeError('(%s): %s' % (path, e))
class DemoTreeStore(Gtk.TreeStore):
__gtype_name__ = 'GtkDemoTreeStore'
def __init__(self, *args):
super(DemoTreeStore, self).__init__(str, Demo, Pango.Style)
self._parent_nodes = {}
self._list_dir(DEMOCODEDIR)
def _list_dir(self, path):
for filename in glob.glob(path + "/[!__]*"):
if os.path.isdir(filename):
self._list_dir(filename)
elif os.path.isfile(filename) and filename.endswith(".py"):
parentname = os.path.dirname(os.path.relpath(filename, DEMOCODEDIR))
if parentname:
parent = self._get_parent_node(parentname)
else:
parent = None
demo = Demo.new_from_file(filename)
self.append(parent, (demo.title, demo, Pango.Style.NORMAL))
def _get_parent_node(self, name):
if name not in self._parent_nodes.keys():
parent_path, current_path = self._get_parent_path(name)
if parent_path:
node = self.append(self._get_parent_node(parent_path), (current_path, None, Pango.Style.NORMAL))
else:
node = self.append(None, (name, None, Pango.Style.NORMAL))
self._parent_nodes[name] = node
return self._parent_nodes[name]
@staticmethod
def _get_parent_path(path):
index = path.rfind(os.sep)
if index != -1:
return path[0:index], path[index + 1:]
else:
return None, None
class GtkDemoApp(Gtk.Application):
__gtype_name__ = 'GtkDemoWindow'
def __init__(self):
super(GtkDemoApp, self).__init__(application_id='org.gnome.pygobject.gtkdemo')
# Use a GResource to hold the CSS files. Resource bundles are created by
# the glib-compile-resources program shipped with Glib which takes an xml
# file that describes the bundle, and a set of files that the xml
# references. These are combined into a binary resource bundle.
base_path = os.path.abspath(os.path.dirname(__file__))
resource_path = os.path.join(base_path, 'demos/Data/demo.gresource')
resource = Gio.Resource.load(resource_path)
# FIXME: method register() should be without the underscore
# FIXME: see https://bugzilla.gnome.org/show_bug.cgi?id=684319
# Once the resource has been globally registered it can be used
# throughout the application.
Gio.resources_register(resource)
def on_activate(self, app):
self.window = Gtk.ApplicationWindow.new(self)
self.window.set_title('PyGObject GTK+ Code Demos')
self.window.set_default_size(600, 400)
self.setup_default_icon()
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL,
homogeneous=False,
spacing=0)
self.window.add(hbox)
tree = self.create_tree()
hbox.pack_start(child=tree, expand=False, fill=False, padding=0)
# Right vbox contains info/source panels
right_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL,
homogeneous=False,
spacing=0)
hbox.pack_start(child=right_vbox, expand=True, fill=True, padding=0)
stack = Gtk.Stack(transition_type=Gtk.StackTransitionType.SLIDE_LEFT_RIGHT,
homogeneous=True)
switcher = Gtk.StackSwitcher(stack=stack)
right_vbox.pack_start(child=switcher, expand=False, fill=False, padding=0)
right_vbox.pack_start(child=stack, expand=True, fill=True, padding=0)
text_widget, info_buffer = self.create_text_view()
stack.add_titled(text_widget, name='info', title='Info')
self.info_buffer = info_buffer
self.info_buffer.create_tag('title', font='Sans 18')
text_widget, self.source_buffer = self.create_source_view()
stack.add_titled(text_widget, name='source', title='Source')
self.window.show_all()
self.selection_cb(self.tree_view.get_selection(),
self.tree_view.get_model())
@staticmethod
def find_file(base=''):
dir = os.path.join(DEMOCODEDIR, 'data')
logo_file = os.path.join(dir, 'gtk-logo-rgb.gif')
base_file = os.path.join(dir, base)
if (GLib.file_test(logo_file, GLib.FileTest.EXISTS) and
GLib.file_test(base_file, GLib.FileTest.EXISTS)):
return base_file
else:
filename = os.path.join(DEMOCODEDIR, base)
if GLib.file_test(filename, GLib.FileTest.EXISTS):
return filename
# can't find the file
raise IOError('Cannot find demo data file "%s"' % base)
def setup_default_icon(self):
filename = self.find_file('gtk-logo-rgb.gif')
pixbuf = GdkPixbuf.Pixbuf.new_from_file(filename)
transparent = pixbuf.add_alpha(True, 0xff, 0xff, 0xff)
list = []
list.append(transparent)
Gtk.Window.set_default_icon_list(list)
def selection_cb(self, selection, model):
sel = selection.get_selected()
if sel == ():
return
treeiter = sel[1]
title = model.get_value(treeiter, 0)
demo = model.get_value(treeiter, 1)
if demo is None:
return
# Split into paragraphs based on double newlines and use
# textwrap to strip out all other formatting whitespace
description = ''
for paragraph in demo.module.DESCRIPTION.split('\n\n'):
description += '\n'.join(textwrap.wrap(paragraph, 99999))
description += '\n\n' # Add paragraphs back in
f = codecs.open(demo.filename, 'rU', 'utf-8')
code = f.read()
f.close()
# output and style the title
(start, end) = self.info_buffer.get_bounds()
self.info_buffer.delete(start, end)
(start, end) = self.source_buffer.get_bounds()
self.source_buffer.delete(start, end)
start = self.info_buffer.get_iter_at_offset(0)
end = start.copy()
self.info_buffer.insert(end, title)
start = end.copy()
start.backward_chars(len(title))
self.info_buffer.apply_tag_by_name('title', start, end)
self.info_buffer.insert(end, '\n')
# output the description
self.info_buffer.insert(end, description)
# output the code
start = self.source_buffer.get_iter_at_offset(0)
end = start.copy()
self.source_buffer.insert(end, code)
@staticmethod
def row_activated_cb(view, path, col, store):
iter = store.get_iter(path)
demo = store.get_value(iter, 1)
if demo is not None:
store.set_value(iter, 2, Pango.Style.ITALIC)
try:
demo.module.main()
except Exception as e:
print(demo.module)
raise e
finally:
store.set_value(iter, 2, Pango.Style.NORMAL)
def create_tree(self):
tree_store = DemoTreeStore()
tree_view = Gtk.TreeView()
self.tree_view = tree_view
tree_view.set_model(tree_store)
selection = tree_view.get_selection()
selection.set_mode(Gtk.SelectionMode.BROWSE)
tree_view.set_size_request(200, -1)
cell = Gtk.CellRendererText()
column = Gtk.TreeViewColumn(title='Widget (double click for demo)',
cell_renderer=cell,
text=0,
style=2)
first_iter = tree_store.get_iter_first()
if first_iter is not None:
selection.select_iter(first_iter)
selection.connect('changed', self.selection_cb, tree_store)
tree_view.connect('row_activated', self.row_activated_cb, tree_store)
tree_view.append_column(column)
# tree_view.expand_all()
tree_view.set_headers_visible(False)
scrolled_window = Gtk.ScrolledWindow(hadjustment=None,
vadjustment=None)
scrolled_window.set_policy(Gtk.PolicyType.NEVER,
Gtk.PolicyType.AUTOMATIC)
scrolled_window.add(tree_view)
label = Gtk.Label(label='Widget (double click for demo)')
box = Gtk.Notebook()
box.append_page(scrolled_window, label)
tree_view.grab_focus()
return box
@staticmethod
def create_scrolled_window():
scrolled_window = Gtk.ScrolledWindow(hadjustment=None,
vadjustment=None)
scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC,
Gtk.PolicyType.AUTOMATIC)
scrolled_window.set_shadow_type(Gtk.ShadowType.IN)
return scrolled_window
def create_text_view(self):
text_view = Gtk.TextView()
buffer = Gtk.TextBuffer()
text_view.set_buffer(buffer)
text_view.set_editable(False)
text_view.set_cursor_visible(False)
scrolled_window = self.create_scrolled_window()
scrolled_window.add(text_view)
text_view.set_wrap_mode(Gtk.WrapMode.WORD)
text_view.set_pixels_above_lines(2)
text_view.set_pixels_below_lines(2)
return scrolled_window, buffer
def create_source_view(self):
font_desc = Pango.FontDescription('monospace 13')
if GtkSource:
lang_mgr = GtkSource.LanguageManager.get_default()
# print(lang_mgr.get_language_ids())
lang = lang_mgr.get_language('python3')
buffer = GtkSource.Buffer()
buffer.set_language(lang)
buffer.set_highlight_syntax(True)
view = GtkSource.View()
view.set_buffer(buffer)
view.set_show_line_numbers(True)
scrolled_window = self.create_scrolled_window()
scrolled_window.add(view)
else:
scrolled_window, buffer = self.create_text_view()
view = scrolled_window.get_child()
view.modify_font(font_desc)
view.set_wrap_mode(Gtk.WrapMode.NONE)
return scrolled_window, buffer
def run(self, argv):
self.connect('activate', self.on_activate)
return super(GtkDemoApp, self).run(argv)
def main(argv):
"""Entry point for demo manager"""
app = GtkDemoApp()
return app.run(argv)
if __name__ == '__main__':
SystemExit(main(sys.argv))
GtkSource安装
要显示Python风格的源代码,需要安装GtkSource
具体方法为:
jhbuild build gtksourceview
安装完成后还需要把gtksourceview一些样式装到系统本地路径
cd /Users/xiaosanyu/gtk/source/gtksourceview
./configure
make
make install
可惜我的安装好后,只能显示行号,没有彩色关键字,报如下错误
(gtk-demo.py:22336): Gdk-WARNING **: GdkQuartzDisplay does not implement the monitor vfuncs
/Applications/Project/Python/project/PYGUI/pygtk3/gtk-demo.py:333: Warning: unknown option bit(s) set
buffer.set_language(lang)
/Applications/Project/Python/project/PYGUI/pygtk3/gtk-demo.py:333: Warning: g_regex_match_full: assertion ‘regex != NULL’ failed
buffer.set_language(lang)
/Applications/Project/Python/project/PYGUI/pygtk3/gtk-demo.py:333: Warning: g_regex_replace_eval: assertion ‘regex != NULL’ failed
buffer.set_language(lang)
/Applications/Project/Python/project/PYGUI/pygtk3/gtk-demo.py:333: Warning: g_regex_unref: assertion ‘regex != NULL’ failed
buffer.set_language(lang)
(gtk-demo.py:22336): GtkSourceView-WARNING **: in file /usr/local/share/gtksourceview-3.0/language-specs/python3.lang: style ‘python:module-handler’ not defined
(gtk-demo.py:22336): GtkSourceView-WARNING **: Failed to load ‘/usr/local/share/gtksourceview-3.0/language-specs/python3.lang’: style override used with wildcard context reference in language ‘python3’ in ref ‘def:line-continue’
貌似是正则库没有装好,还请有装好的朋友给个参考方法
20160804
更新:pcre正则匹配原因找到了
修改/Users/xiaosanyu/gtk/source/glib/glib/gregex.c
大约1420行
re = pcre_compile2 (pattern, compile_options, &errcode,
&errmsg, &erroffset, NULL);
改成
re = pcre_compile2 (pattern, 0, &errcode,
&errmsg, &erroffset, NULL);
然后重新编译glib
jhbuild build glib
OK,大功告成,开心~~~~~