[Python-checkins] r64668 - sandbox/trunk/ttk-gsoc/samples/theming.py
guilherme.polo
python-checkins at python.org
Wed Jul 2 20:04:07 CEST 2008
Author: guilherme.polo
Date: Wed Jul 2 20:04:06 2008
New Revision: 64668
Log:
Images can be edited and removed now;
Added support for image format specification;
Removed self._custom_options as it has no uses, at least for now;
The sash between the top and bottom frames is adjusted just when the app starts now.
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 Wed Jul 2 20:04:06 2008
@@ -6,10 +6,11 @@
# XXX ToDo List:
# * Save/Load style changes, maybe.
-# * Add a way to edit images/elements.
+# * Add a way to edit elements.
# * Add pre-defined elements for the current theme:
# - Just after editing elements feature is added.
+import os
import sys
import ttk
import pprint
@@ -19,6 +20,8 @@
from tkMessageBox import showwarning, showerror
from tkFileDialog import askopenfilename
+IMAGE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "img")
+
def map_widgets():
"""Maps Ttk widgets to their respective layout(s), factory and
possibly others."""
@@ -247,16 +250,22 @@
return False
-class NewImage(NewOption): # reusing buttonbox
- """A dialog that asks for a image name and image path or data."""
+class ImageDialog(NewOption): # reusing buttonbox
+ """A dialog that asks for a image name and image path or data and then
+ creates a PhotoImage from the data, or, receives data to edit."""
- def __init__(self, master, title="New Image"):
+ def __init__(self, master, title="New Image", image=None):
+ self._editing = True if image else False
+ self._image = image
NewOption.__init__(self, master, title)
def body(self, master):
lbl = ttk.Label(master, text="Image name")
self.img_name = ttk.Entry(master)
+ lbl_format = ttk.Label(master, text="Image Format")
+ self.img_format = ttk.Entry(master)
+
lbl_val = ttk.Label(master, text="Image path")
self.img_path = ttk.Entry(master)
browse = ttk.Button(master, text="Find", command=self._find_image)
@@ -264,21 +273,34 @@
lbl_other = ttk.Label(master, text="or")
lbl_data = ttk.Label(master, text="Image data")
- self.img_data = ScrolledText(master, width=60, height=6)
+ self.img_data = ScrolledText(master, width=60, height=8)
lbl.grid(row=0, column=0, padx=6, sticky='e')
self.img_name.grid(row=0, column=1, padx=6, columnspan=2, sticky='ew')
- lbl_val.grid(row=1, column=0, padx=6, pady=6, sticky='e')
- self.img_path.grid(row=1, column=1, padx=6, sticky='ew')
- browse.grid(row=1, column=2, padx=6, sticky='e')
- lbl_other.grid(row=2, columnspan=3, pady=3)
- lbl_data.grid(row=3, column=0, padx=6, sticky='new')
- self.img_data.grid(row=3, column=1, columnspan=2)
+ lbl_format.grid(row=1, column=0, padx=6, sticky='e', pady=6)
+ self.img_format.grid(row=1, column=1, padx=6, columnspan=2,
+ sticky='ew', pady=6)
+ lbl_val.grid(row=2, column=0, padx=6, sticky='e')
+ self.img_path.grid(row=2, column=1, padx=6, sticky='ew')
+ browse.grid(row=2, column=2, padx=6, sticky='e')
+ lbl_other.grid(row=3, columnspan=3, pady=3)
+ lbl_data.grid(row=4, column=0, padx=6, sticky='new')
+ self.img_data.grid(row=4, column=1, columnspan=2)
master.grid_columnconfigure(1, weight=1)
self.resizable(False, False)
+ if self._editing:
+ self.img_name.insert(0, self._image.name)
+ self.img_name['state'] = 'readonly'
+ self.img_format.insert(0, self._image['format'])
+
+ if self._image['file']:
+ self.img_path.insert(0, self._image['file'])
+ else:
+ self.img_data.insert('1.0', self._image['data'])
+
def validate(self):
"""Verify that a name was defined and only one between data and
image path has been defined."""
@@ -293,18 +315,54 @@
"a image path or the image data.", parent=self)
return False
+ if self._editing:
+ if not self._change_image(img_name, img_path, img_data):
+ return False
+ else:
+ if not self._create_image(img_name, img_path, img_data):
+ return False
+
+ return True
+
+ def _create_image(self, img_name, img_path, img_data):
+ """Create a new PhotoImage."""
try:
+ kwargs = {'name': img_name}
+ if self.img_format.get():
+ kwargs['format'] = self.img_format.get()
+
if img_data:
- self.result = Tkinter.PhotoImage(name=img_name, data=img_data)
+ kwargs['data'] = img_data
else:
- self.result = Tkinter.PhotoImage(name=img_name, file=img_path)
+ kwargs['file'] = img_path
+
+ self.result = Tkinter.PhotoImage(**kwargs)
except Tkinter.TclError, err:
showerror("Error creating image", err, parent=self)
return False
+ else:
+ return True
- return True
+ def _change_image(self, img_name, img_path, img_data):
+ """Change an existing PhotoImage."""
+ try:
+ if self.img_format.get():
+ self._image['format'] = self.img_format.get()
+
+ if img_path:
+ self._image['file'] = img_path
+ self._image['data'] = ''
+ else:
+ self._image['file'] = ''
+ self._image['data'] = img_data
+ except Tkinter.TclError, err:
+ showerror("Error updating image", err, parent=self)
+ return False
+ else:
+ return True
def _find_image(self):
+ """Open a file browser and search for the image path."""
path = askopenfilename(parent=self)
if path:
# erase previous content
@@ -406,7 +464,7 @@
self._style = ttk.Style(self.master)
self._current_widget = {'layout': None, 'widget': None}
- self._custom_options = {} # custom options per widget
+ self._images = {}
self.__create_menu()
self.__setup_widgets()
@@ -555,7 +613,7 @@
self._update_layout_text(layout[layout.find('.') + 1:])
self.layouttext.layout = layout
- def _ask_new_frame_opt(self, frame, func):
+ def _new_frame_opt(self, frame, func):
"""Open a dialog asking for a new option to be added in the
specified frame and then add it."""
widget = self._current_widget
@@ -569,14 +627,9 @@
dlg = NewOption(self.master)
if dlg.result is not None:
option, value = dlg.result
-
- if layout_name not in self._custom_options:
- self._custom_options[layout_name] = []
-
- self._custom_options[layout_name].append(option)
self._add_opt_frame(frame, func, layout_name, option, value)
- def _ask_new_element(self, frame):
+ def _new_element(self, frame):
"""Open a dialog for getting data for a new style element and then
create it."""
dlg = NewElement(self.master, imglist=self._imagelist)
@@ -595,8 +648,8 @@
# create element
try:
- self._style.element_create(name, dlg.result['etype'], *args,
- **dlg.result['opts'])
+ self._style.element_create(name,
+ dlg.result['etype'], *args, **dlg.result['opts'])
except Tkinter.TclError, err:
showerror("Element couldn't be created",
"The specified element couldn'be created, reason: "
@@ -605,16 +658,42 @@
# add it to the list
self._elems.set(name)
self._elems['values'] = (self._elems['values'] or ()) + (name, )
+ # the new element could have affected the current widget, so
+ # we need to update the preview area.
+ treeview = self._tv_widgets
+ self._change_preview(treeview, invalid=True)
- def _ask_new_image(self):
+ def _new_image(self):
"""Add a new image to the image combobox. This image can be used
in any widget layout."""
- dlg = NewImage(self.master)
+ dlg = ImageDialog(self.master)
if dlg.result: # add new image to the images list
img = dlg.result
- self._imagelist.set(img.name)
+ img_name = img.name
+ self._images[img_name] = img
+ self._imagelist.set(img_name)
self._imagelist['values'] = (self._imagelist['values'] or ()) + \
- (img.name, )
+ (img_name, )
+
+ def _edit_image(self):
+ """Edit current selected image in imagelist."""
+ img_name = self._imagelist.get()
+ if not img_name:
+ return
+
+ ImageDialog(self.master, "Editing Image", self._images[img_name])
+
+ def _remove_image(self):
+ """Remove current selected image in imagelist."""
+ img_name = self._imagelist.get()
+ if not img_name:
+ return
+
+ del self._images[img_name]
+ values = set(self._imagelist['values']) - set([img_name])
+ self._imagelist['values'] = list(values)
+ value = values.pop() if values else ''
+ self._imagelist.set(value)
def _change_theme(self, event):
"""New theme selected at themes combobox, change current theme."""
@@ -662,7 +741,7 @@
left.pack(side='left', fill='y')
# widget listing
self._tv_widgets = ScrolledTreeview(left, selectmode='browse')
- self._tv_widgets.pack(side='top', fill='y', anchor='w', expand=True)
+ self._tv_widgets.pack(side='top', fill='y', expand=True)
self._tv_widgets.heading('#0', text="Widgets")
self._tv_widgets.bind('<<TreeviewSelect>>', self._change_preview)
@@ -672,27 +751,26 @@
# preview area
self._preview_area = ttk.Frame(topright, width=200)
- self._preview_area.pack(anchor='center', side='left', expand=True,
- fill='both', padx=12)
+ self._preview_area.pack(side='left', expand=True, fill='both', padx=12)
# options, images and themes
frames = ttk.Frame(topright)
frames.pack(side='right', anchor='n')
# style notebook and frames
styleframe = ttk.Labelframe(frames, text="Style", padding=6)
- styleframe.pack(fill='both', anchor='n')
+ styleframe.pack(fill='both')
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,
+ command=lambda: self._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,
+ command=lambda: self._new_frame_opt(self._mapframe,
self._style.map))
newmopt.pack(side='bottom', anchor='e')
self._mapframe.pack()
@@ -701,7 +779,7 @@
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))
+ command=lambda: self._new_element(elemframe))
newelem.pack(side='bottom', anchor='e')
elemframe.pack()
# themes
@@ -711,7 +789,7 @@
state='readonly')
themes.set("Pick one")
themes.bind('<<ComboboxSelected>>', self._change_theme)
- themes.pack(fill='x')
+ themes.pack(fill='x', pady=6)
# add frames to the style notebook
stylenb.add(self._configframe, text="Configure")
stylenb.add(self._mapframe, text="Map")
@@ -719,16 +797,32 @@
stylenb.add(themeframe, text="Themes")
stylenb.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 = ttk.Labelframe(frames, padding=6)
imagesframe.pack(fill='x', pady=12)
+ iframe = ttk.Frame(imagesframe)
+ imagesframe['labelwidget'] = iframe
+ self.__img_add = Tkinter.PhotoImage(file=os.path.join(IMAGE_DIR,
+ 'add.gif'))
+ self.__img_edit = Tkinter.PhotoImage(file=os.path.join(IMAGE_DIR,
+ 'stock_properties.gif'))
+ self.__img_del = Tkinter.PhotoImage(file=os.path.join(IMAGE_DIR,
+ 'remove.gif'))
+ ilbl = ttk.Label(iframe, text="Images")
+ iadd = ttk.Button(iframe, image=self.__img_add.name,
+ style='Toolbutton', command=self._new_image)
+ iedit = ttk.Button(iframe, image=self.__img_edit.name,
+ style='Toolbutton', command=self._edit_image)
+ iremove = ttk.Button(iframe, image=self.__img_del.name,
+ style='Toolbutton', command=self._remove_image)
+ ilbl.pack(side='left')
+ iadd.pack(side='left')
+ iedit.pack(side='left')
+ iremove.pack(side='left')
+ self._imagelist = ttk.Combobox(imagesframe, state='readonly')
+ self._imagelist.pack(fill='x')
# bottom frame (layout)
- bottom = ttk.Frame(paned, padding=[0, 0, 6])
+ bottom = ttk.Frame(paned)
bottom.pack(side='bottom')
layoutframe = ttk.Labelframe(bottom, text="Layout", padding=6)
layoutframe.pack(fill='both', expand=True)
@@ -749,13 +843,16 @@
paned.add(top, weight=1)
paned.add(bottom, weight=0)
paned.pack(fill='both', expand=True)
- paned.bind('<Map>', self.__adjust_sash)
+ self.__funcid = paned.bind('<Map>', self.__adjust_sash)
def __adjust_sash(self, event):
- """Adjust sash position between the top frame and the bottom frame."""
+ """Adjust the initial sash position between the top frame and the
+ bottom frame."""
height = self.master.geometry().split('x')[1].split('+')[0]
paned = event.widget
paned.sashpos(0, int(height) - 180)
+ paned.unbind('<Map>', self.__funcid)
+ del self.__funcid
def __fill_treeview(self):
"""Insert available widgets in the treeview."""
More information about the Python-checkins
mailing list