[Python-checkins] r64574 - sandbox/trunk/ttk-gsoc/samples/theming.py
guilherme.polo
python-checkins at python.org
Sat Jun 28 18:18:04 CEST 2008
Author: guilherme.polo
Date: Sat Jun 28 18:18:03 2008
New Revision: 64574
Log:
Dropped py3k support;
Added support for element creation;
Added support for custom layout creation;
Some refactoring;
Modified:
sandbox/trunk/ttk-gsoc/samples/theming.py
Modified: sandbox/trunk/ttk-gsoc/samples/theming.py
==============================================================================
--- sandbox/trunk/ttk-gsoc/samples/theming.py (original)
+++ sandbox/trunk/ttk-gsoc/samples/theming.py Sat Jun 28 18:18:03 2008
@@ -1,26 +1,23 @@
-"""Sample application for playing with Ttk theming.
-A lot of features are missing for now.
+"""
+Sample application for playing with Ttk theming.
+* A lot of features are missing for now.
+
+-- Guilherme Polo, 2008.
"""
# ToDO: Add a way to remove options.
-# Add a way to edit image name and path/data.
+# Add a way to edit images/elements.
+# Handling element options.
# ...
import sys
import ttk
import pprint
-try:
- import cStringIO
- import Tkinter
- from tkSimpleDialog import Dialog
- from tkMessageBox import showwarning
- from tkFileDialog import askopenfilename
-except ImportError: # assuming py3k
- import tkinter as Tkinter
- from tkinter.simpledialog import Dialog
- from tkinter.messagebox import showwarning
- from tkinter.filedialog import askopenfilename
- import io as cStringIO
+import cStringIO
+import Tkinter
+from tkSimpleDialog import Dialog, askstring
+from tkMessageBox import showwarning
+from tkFileDialog import askopenfilename
def available_widgets():
"""Returns a list of Ttk widgets."""
@@ -265,7 +262,7 @@
self.result = Tkinter.PhotoImage(name=img_name, data=img_data)
else:
self.result = Tkinter.PhotoImage(name=img_name, file=img_path)
- except Tkinter.TclError as err:
+ except Tkinter.TclError, err:
showwarning("Error creating image", err, parent=self)
return False
@@ -280,6 +277,66 @@
self.img_path.insert(0, path)
+class NewElement(NewOption): # reusing buttonbox
+ """A dialog for collecting data for a new image element."""
+
+ def __init__(self, master, title="New Element", imglist=None):
+ self._imglist = imglist
+ NewOption.__init__(self, master, title)
+
+ def body(self, master):
+ # element name
+ name = ttk.Label(master, text="Element name")
+ self.name = ttk.Entry(master)
+ # only image type is being supported for now
+ etype = ttk.Label(master, text="Element type")
+ self.etype = ttk.Entry(master)
+ self.etype.insert(0, "image")
+ self.etype['state'] = 'readonly'
+ defimg = ttk.Label(master, text="Default image")
+ self.defimg = ttk.Combobox(master)
+ if self._imglist:
+ self.defimg['values'] = self._imglist['values']
+ # options
+ opts = ttk.Label(master, text="Options")
+ self.opts = ttk.Entry(master)
+ # statespec(s)
+ sspec = ttk.Label(master, text="StateSpec(s)")
+ self.sspec = ttk.Entry(master)
+
+ # place the widgets
+ name.grid(row=0, column=0, sticky='w', padx=6, pady=3)
+ self.name.grid(row=0, column=1, pady=3, sticky='ew')
+ etype.grid(row=0, column=2, sticky='w', padx=6, pady=3)
+ self.etype.grid(row=0, column=3, pady=3)
+ defimg.grid(row=1, column=0, sticky='w', padx=6, pady=3)
+ self.defimg.grid(row=1, column=1, pady=3, sticky='ew')
+ opts.grid(row=1, column=2, sticky='w', padx=6, pady=3)
+ self.opts.grid(row=1, column=3, pady=3)
+ sspec.grid(row=2, column=0, sticky='w', padx=6, pady=3)
+ self.sspec.grid(row=2, column=1, columnspan=3, sticky='ew', pady=3)
+
+ self.resizable(False, False)
+
+ def validate(self):
+ """Check if an, apparently, correct element specification has been
+ entered."""
+ entries = [('elementname', self.name), ('etype', self.etype),
+ ('def', self.defimg), ('sspec', self.sspec), ('opts', self.opts)]
+ values = {}
+ for name, entry in entries:
+ values[name] = entry.get()
+
+ if not all((values['elementname'], values['etype'], values['def'])):
+ showwarning("Invalid element specification",
+ "You need to specify a name, a type and a default image "
+ "at least.", parent=self)
+ return False
+
+ self.result = values
+ return True
+
+
class MainWindow(object):
def __init__(self, master, title=None):
frame = ttk.Frame(master)
@@ -314,10 +371,17 @@
complement = ''
opts = {}
- if '.' in widget_name: # horizontal/vertical layout
+ if '.' in widget_name: # horizontal/vertical layout (maybe)
complement, widget_name = widget_name.split('.')
opts = {'orient': complement.lower()}
+ # check if this is a widget or a custom layout
+ if not hasattr(ttk, widget_name): # custom layout
+ self._current_widget['layout'] = "Custom.T%s.%s" % (complement,
+ widget_name)
+ self._update_layout_text()
+ return
+
# create a sample widget
if widget.get('factory', None):
widget_class = getattr(ttk, widget_name)
@@ -343,13 +407,14 @@
"""Update the layout text for the current widget."""
layout_name = self._current_widget['layout']
output = cStringIO.StringIO()
- layout = pprint.pprint(self._style.layout(layout_name), stream=output)
+ pprint.pprint(self._style.layout(layout_name), stream=output)
layout = output.getvalue()
output.close()
self.layouttext.delete('1.0', 'end') # clear current text
self.layouttext.insert('1.0', layout) # set new text
def _remove_previous_widgets(self):
+ """Remove widgets from the style frames."""
self._current_options = self._current_options or []
# remove previous widgets
for widget in self._current_options:
@@ -364,6 +429,7 @@
self._update_style(self._style.map, self._mapframe)
def _update_style(self, func, frame):
+ """Treeview selection changed, update the displayed style."""
widget = self._current_widget
layout_name = widget['layout']
raw_name = layout_name[layout_name.find('.', 1) + 1:]
@@ -374,6 +440,17 @@
for opt_name, opt_value in options.items():
self._add_opt_frame(frame, func, layout_name, opt_name, opt_value)
+ def _add_custom_layout(self):
+ """Create a new, and empty, custom layout."""
+ result = askstring("New Layout", "Layout name")
+ if result:
+ # create an empty layout
+ self._style.layout(result, '')
+ # create a "semi-widget"
+ treeview = self._tv_custom
+ widget_d = {'factory': None, 'layouts': None}
+ self._add_widget(result, widget_d, treeview)
+
def _add_opt_frame(self, frame, func, layout_name, opt_name, opt_value):
"""Add a new option to a frame."""
def change_opt(option, text):
@@ -413,7 +490,7 @@
return
text = self.layouttext.get('1.0', 'end')
- # XXX Warning, eval usage!
+ # XXX Warning: eval usage!
self._style.layout(layout, eval(text))
def _reset_layout(self):
@@ -442,7 +519,39 @@
option, value = dlg.result
self._add_opt_frame(frame, func, layout_name, option, value)
- def _new_image(self):
+ def _ask_new_element(self, frame):
+ """Open a dialog for getting data for a new style element."""
+ dlg = NewElement(self.master, imglist=self._imagelist)
+ if dlg.result:
+ name = dlg.result['elementname']
+ # format args
+ if dlg.result['sspec']:
+ # XXX Warning: eval usage!
+ sspec = eval(dlg.result['sspec'])
+ if dlg.result['sspec'].count('(') == 1:
+ # only one statespec defined
+ sspec = (sspec, )
+ else:
+ sspec = ()
+ args = (dlg.result['def'], ) + sspec
+
+ # format opts (XXX Not done)
+ #if dlg.result['opts']:
+ # print dlg.result['opts']
+
+ # create element
+ try:
+ self._style.element_create(name, dlg.result['etype'], *args)
+ except Tkinter.TclError, err:
+ showwarning("Element couldn't be created",
+ "The specified element couldn'be created, reason: "
+ "\n%s" % err, parent=self.master)
+
+ # add it to the list
+ self._elems.set(name)
+ self._elems['values'] = (self._elems['values'] or ()) + (name, )
+
+ def _ask_new_image(self):
"""Add a new image to the image combobox. This image can be used
in any widget layout."""
dlg = NewImage(self.master)
@@ -452,6 +561,21 @@
self._imagelist['values'] = (self._imagelist['values'] or ()) + \
(img.name, )
+ def _add_widget(self, name, opts, treeview=None):
+ """Add a new widget to self._widget."""
+ treeview = treeview or self._tv_widgets
+ children = opts.pop('layouts') or ()
+
+ parent = treeview.insert('', 'end', text=name)
+ self._widget[name] = {'tv_item': parent, 'class': None}
+ self._widget[name].update(opts)
+
+ for child in children:
+ child_name = '%s.%s' % (child, name)
+ item = treeview.insert(parent, 'end', text=child_name)
+ self._widget[child_name] = {'tv_item': item, 'class': None}
+ self._widget[child_name].update(opts)
+
def __create_menu(self):
menu = Tkinter.Menu()
self.master['menu'] = menu
@@ -462,7 +586,12 @@
file_menu.add_command(label="Exit", underline=1,
command=self.master.destroy)
+ layout_menu = Tkinter.Menu(menu, tearoff=False)
+ layout_menu.add_command(label="New layout",
+ command=self._add_custom_layout)
+
menu.add('cascade', menu=file_menu, label="File", underline=0)
+ menu.add('cascade', menu=layout_menu, label="Custom Layouts")
def __setup_widgets(self):
"""Create and layout widgets."""
@@ -472,26 +601,23 @@
top = ttk.Frame(paned)
top.pack(side='top', fill='both', expand=True)
- # top left frame (widget listing, images)
+ # top left frame (widget listing, custom layouts, images)
left = ttk.Frame(top)
left.pack(side='left', fill='y')
- tframe = ttk.Frame(left)
- tframe.pack(side='top', fill='y', expand=True)
- self._tv_widgets = treeview = ScrolledTreeview(tframe,
- selectmode='browse')
- treeview.pack(side='left', fill='y', expand=True)
- treeview.heading('#0', text="Widgets")
- treeview.bind('<<TreeviewSelect>>', self._change_preview)
- # images
- imagesframe = ttk.Labelframe(left, text="Images", padding=6)
- self._imagelist = ttk.Combobox(imagesframe, state='readonly')
- self._imagelist.pack(fill='x', pady=6)
- newimg = ttk.Button(imagesframe, text="Add Image",
- command=self._new_image)
- newimg.pack(side='bottom', anchor='e')
- imagesframe.pack(fill='x', pady=12)
+ # widget listing
+ self._tv_widgets = ScrolledTreeview(left, selectmode='browse')
+ self._tv_widgets.pack(side='top', fill='y', anchor='w', expand=True)
+ self._tv_widgets.heading('#0', text="Widgets")
+ self._tv_widgets.bind('<<TreeviewSelect>>', self._change_preview)
+ # custom layouts
+ self._tv_custom = ScrolledTreeview(left, selectmode='browse',
+ height=4)
+ self._tv_custom.pack(side='top', anchor='w')
+ self._tv_custom.heading('#0', text="Custom Layouts")
+ self._tv_custom.bind('<<TreeviewSelect>>', self._change_preview)
- # top right frame (preview, style conf, style map, themes)
+ # top right frame (preview, style conf, style map, elements, themes and
+ # images)
topright = ttk.Frame(top)
topright.pack(side='top', fill='both', expand=True, padx=6)
@@ -505,19 +631,31 @@
frames.pack(side='right', anchor='n')
# style notebook and frames
styleframe = ttk.Labelframe(frames, text="Style", padding=6)
+ styleframe.pack(fill='both', anchor='n')
stylenb = ttk.Notebook(styleframe)
+ # style configure
self._configframe = ttk.Frame(stylenb, padding=6)
newopt = ttk.Button(self._configframe, text="Add option",
command=lambda: self._ask_new_frame_opt(self._configframe,
self._style.configure))
newopt.pack(side='bottom', anchor='e')
self._configframe.pack()
+ # style map
self._mapframe = ttk.Frame(stylenb, padding=6)
newmopt = ttk.Button(self._mapframe, text="Add option",
command=lambda: self._ask_new_frame_opt(self._mapframe,
self._style.map))
newmopt.pack(side='bottom', anchor='e')
self._mapframe.pack()
+ # style elements
+ elemframe = ttk.Frame(stylenb, padding=6)
+ self._elems = ttk.Combobox(elemframe, state='readonly')
+ self._elems.pack(fill='x', pady=6)
+ newelem = ttk.Button(elemframe, text="New element",
+ command=lambda: self._ask_new_element(elemframe))
+ newelem.pack(side='bottom', anchor='e')
+ elemframe.pack()
+ # themes
themeframe = ttk.Frame(stylenb, padding=6)
themeframe.pack(padx=6)
themes = ttk.Combobox(themeframe, values=self._style.theme_names(),
@@ -525,11 +663,20 @@
themes.set("Pick one")
themes.bind('<<ComboboxSelected>>', self._change_theme)
themes.pack(fill='x')
+ # add frames to the style notebook
stylenb.add(self._configframe, text="Configure")
stylenb.add(self._mapframe, text="Map")
+ stylenb.add(elemframe, text="Elems")
stylenb.add(themeframe, text="Themes")
stylenb.pack(fill='both', anchor='n')
- styleframe.pack(fill='both', anchor='n')
+ # images frame
+ imagesframe = ttk.Labelframe(frames, text="Images", padding=6)
+ self._imagelist = ttk.Combobox(imagesframe, state='readonly')
+ self._imagelist.pack(fill='x', pady=6)
+ newimg = ttk.Button(imagesframe, text="Add Image",
+ command=self._ask_new_image)
+ newimg.pack(side='bottom', anchor='e')
+ imagesframe.pack(fill='x', pady=12)
# bottom frame (layout)
bottom = ttk.Frame(paned, padding=[0, 0, 6])
@@ -565,17 +712,7 @@
self._widget = {}
widgets = available_widgets()
for name, opts in sorted(widgets.items()):
- children = opts.pop('layouts') or ()
-
- parent = self._tv_widgets.insert('', 'end', text=name)
- self._widget[name] = {'tv_item': parent, 'class': None}
- self._widget[name].update(opts)
-
- for child in children:
- child_name = '%s.%s' % (child, name)
- item = self._tv_widgets.insert(parent, 'end', text=child_name)
- self._widget[child_name] = {'tv_item': item, 'class': None}
- self._widget[child_name].update(opts)
+ self._add_widget(name, opts)
def main(args=None):
More information about the Python-checkins
mailing list