[Python-checkins] r62479 - in sandbox/trunk/ttk-gsoc: README lib-tk lib-tk/Ttk.py samples samples/combo_themes.py samples/theme_selector.py
guilherme.polo
python-checkins at python.org
Thu Apr 24 17:52:15 CEST 2008
Author: guilherme.polo
Date: Thu Apr 24 17:52:14 2008
New Revision: 62479
Log:
Initial code, not complete and several design questions for now.
A short README is included telling what is required to run the
samples included.
Added:
sandbox/trunk/ttk-gsoc/README
sandbox/trunk/ttk-gsoc/lib-tk/
sandbox/trunk/ttk-gsoc/lib-tk/Ttk.py
sandbox/trunk/ttk-gsoc/samples/
sandbox/trunk/ttk-gsoc/samples/combo_themes.py
sandbox/trunk/ttk-gsoc/samples/theme_selector.py
Added: sandbox/trunk/ttk-gsoc/README
==============================================================================
--- (empty file)
+++ sandbox/trunk/ttk-gsoc/README Thu Apr 24 17:52:14 2008
@@ -0,0 +1,13 @@
+Testing Code
+============
+
+You will need Python with a _tkinter compiled against Tcl/Tk 8.5 or
+Tile[1] has to be installed. I have tested it with python-trunk and
+release25-maint repos.
+
+Given that you have the requirements, you should be able to run the
+samples passing the appropriate PYTHONPATH or placing the Ttk module
+somewhere in sys.path.
+
+
+[1] I didn't test it with Tile yet, not sure if it will be detected.
Added: sandbox/trunk/ttk-gsoc/lib-tk/Ttk.py
==============================================================================
--- (empty file)
+++ sandbox/trunk/ttk-gsoc/lib-tk/Ttk.py Thu Apr 24 17:52:14 2008
@@ -0,0 +1,354 @@
+"""Ttk wrapper.
+
+This module provides classes to allow using Tk themed widget set.
+
+Ttk is based on a revised and enhanced version of
+TIP #48 (http://tip.tcl.tk/48) specified style engine.
+
+Its basic idea is to separate, to the extent possible, the code
+implementing a widget's behavior from the code implementing its
+appearance. Widget class bindings are primarily responsible for
+maintaining the widget state and invoking callbacks, all aspects
+of the widgets appearance lies at Themes.
+"""
+
+__version__ = "Not ready for use, and incomplete"
+
+import Tkinter
+import _tkinter
+
+# Check if Ttk is available for use
+if Tkinter.TkVersion < 8.5:
+ # Tk version is "too old", but if Tile is around Ttk still can be used
+ # XXX All this verbosity below could be removed.
+ # XXX Looking at FixTk.py it seems something for tile should be added.
+ _tkinter.create(
+ None, # screename
+ '', # basename
+ '', # className
+ 0, # interactive
+ 0, # wantobjects
+ 1, # wantTk, setting this to False Tk_Init doesn't get called,
+ # but eval won't work then
+ 0, # sync
+ None # use
+ ).eval('package require tile')
+
+# If we are here, then Ttk is available for use =)
+
+class Style(object):
+ """Manipulate style database."""
+
+ def style_configure(self, style, **kw):
+ """Sets the default value of the especified option(s) in style."""
+ # XXX I renamed this method so it doesn't conflict with Misc.configure
+ # but maybe this one could be removed.
+ raise NotImplementedError
+
+
+ def map(self, style, **kw):
+ raise NotImplementedError
+
+
+ def lookup(self, style, option, state="normal", default=None):
+ """Returns the value specified for option for given style in
+ state, using the standard lookup rules for element options.
+ state is a list of state names; if omitted, it defaults to
+ "normal". If the default argument is present, it is used as a
+ fallback value in case no specification for option is
+ found."""
+ # XXX Redo this docstring after understanding how lookup
+ # works
+ raise NotImplementedError
+
+
+ def layout(self, style, layoutspec=None):
+ """Define the widget layout for given style. If layoutspec is
+ omitted, return the layout specification for given style.
+
+ The format of layoutspec is described below:
+
+ LAYOUTS
+
+ A layout specifies a list of elements, each followed by
+ one or more options specifying how to arrange the element.
+ The layout mechanism uses a simplified version of the pack
+ geometry manager: given an initial cavity, each element is
+ allocated a parcel. Valid options are:
+
+ side: whichside
+ Specifies which side of the cavity to place the
+ element; one of top, right, bottom or left. If
+ omitted, the element occupies the entire cavity.
+
+ sticky: nswe
+ Specifies where the element is placed inside its
+ allocated parcel.
+
+ children: [sublayout... ]
+ Specifies a list of elements to place inside the
+ element
+ """
+ # XXX I haven't used this yet, but it looks like a more
+ # appropriate way of passing layoutspec should be done
+ return self.tk.call("ttk::style", "layout", style, layoutspec)
+
+
+ def element_create(self, elementname, type, **kw):
+ """Create a new element in the current theme of given type."""
+ raise NotImplementedError
+
+
+ def element_names(self):
+ """Returns the list of elements defined in the current theme."""
+ return self.tk.call("ttk::style", "element", "names")
+
+
+ def element_options(self, element):
+ """Return the list of element's options."""
+ return self.tk.call("ttk::style", "element", "options", element)
+
+
+ def theme_create(self, themename, **kw):
+ raise NotImplementedError
+
+
+ def theme_settings(self, themename, script):
+ """Temporarily sets the current theme to themename, evaluate
+ script, then restore the previous theme."""
+ raise NotImplementedError
+
+
+ def theme_names(self):
+ """Returns a list of all known themes."""
+ return self.tk.call("ttk::style", "theme", "names")
+
+
+ def theme_use(self, themename):
+ """Sets the current theme to themename, and refreshes all widgets."""
+ self.tk.call("ttk::style", "theme", "use", themename)
+
+
+class Widget(Tkinter.Widget, Style):
+ # XXX after rereading the ttk description, it looks like
+ # this class shouldn't subclass Style
+ """Base class for Tk themed widgets."""
+
+ def __init__(self, master, widgetName, cnf={}, kw={}, extra=()):
+ """Constructs a Ttk Widget with the parent master.
+
+ STANDARD OPTIONS
+
+ class, cursor, takefocus, style
+
+ SCROLLABLE WIDGET OPTIONS
+
+ xscrollcommand, yscrollcommand
+
+ LABEL WIDGET OPTIONS
+
+ text, textvariable, underline, image, compound, width
+
+ WIDGET STATES
+
+ active, disabled, focus, pressed, selected, background,
+ readonly, alternate, invalid
+ """
+ Tkinter.Widget.__init__(self, master, widgetName, cnf, kw, extra)
+
+
+ def instate(self, statespec, callback=None, *args):
+ """Test the widget's state.
+
+ If callback is not especified, returns 1 if the widget state
+ matches statespec and 0 otherwise. If callback is specified,
+ then it will be invoked with *args if the widget state matches
+ statespec."""
+ ret = self.tk.call(self._w, "instate", statespec)
+ if ret and callback:
+ return callback(*args)
+
+ return ret
+
+
+ def state(self, statespec=None):
+ """Modify or inquire widget state.
+
+ Widget state is returned if statespec is None, otherwise it is
+ set according to the statespec flags and then a new state spec
+ is returned indicating which flags were changed."""
+ return self.tk.call(self._w, "state", statespec)
+
+
+class Button(Widget):
+ """Ttk Button widget, displays a textual label and/or image, and
+ evaluates a command when pressed."""
+
+ def __init__(self, master=None, cnf={}, **kw):
+ """Construct a Ttk Button widget with the parent master.
+
+ STANDARD OPTIONS
+
+ class, compound, cursor, image, state, style, takefocus,
+ text, textvariable, underline, width
+
+ WIDGET-SPECIFIC OPTIONS
+
+ command, default, width
+ """
+
+ Widget.__init__(self, master, "ttk::button", cnf, kw)
+
+
+class Checkbutton(Widget):
+ """Ttk Checkbutton widget which is either in on- or off-state."""
+
+ def __init__(self, master=None, cnf={}, **kw):
+ """Construct a Ttk Checkbutton widget with the parent master.
+
+ STANDARD OPTIONS
+
+ class, compound, cursor, image, state, style, takefocus,
+ text, textvariable, underline, width
+
+ WIDGET-SPECIFIC OPTIONS
+
+ command, offvalue, onvalue, variable
+ """
+ Widget.__init__(self, master, "ttk::checkbutton", cnf, kw)
+
+
+ def invoke(self):
+ """Toggles between the selected and deselected states and
+ invoke the associated command. If the widget is currently
+ selected, sets the option variable to the option offvalue
+ option and deselects the widget; otherwise, sets the option
+ variable to the option onvalue.
+
+ Returns the result of the associated command."""
+ return self.tk.call(self._w, "invoke")
+
+
+class Entry(Widget, Tkinter.Entry):
+ """Ttk Entry widget displays a one-line text string and allows that
+ string to be edited by the user."""
+
+ def __init__(self, master=None, cnf={}, **kw):
+ """Constructs a Ttk Entry widget with the parent master.
+
+ STANDARD OPTIONS
+
+ class, cursor, style, takefocus, xscrollcommand
+
+ WIDGET-SPECIFIC OPTIONS
+
+ exportselection, invalidcommand, justify, show, state,
+ textvariable, validate, validatecommand, width
+
+ VALIDATION MODES
+
+ none, key, focus, focusin, focusout, all
+ """
+ Widget.__init__(self, master, "ttk::entry", cnf, kw)
+
+ # XXX All this following thing will be removed soon
+ #
+ # Tkinter.Entry defines:
+ # delete, get, icursor, index, insert, selection clear,
+ # selection present, selection range, xview, xview moveto,
+ # xview scroll
+ #
+ # Ttk.Widget defines:
+ # instate, state
+ #
+ # Misc (Ttk.Widget -> Tkinter.Widget -> Misc) defines:
+ # cget, configure
+ #
+ # This leaves bbox, identify and validate to be defined here
+
+ def bbox(self, index):
+ """Return a tuple of (x, y, width, height) which describes the
+ bounding box of the character given by index."""
+ return self.tk.call(self._w, "bbox", index)
+
+
+ def identify(self, x, y):
+ """Returns the name of the element at position x, y, or the
+ empty string if the coordinates are outside the window."""
+ return self.tk.call(self._w, "identify", x, y)
+
+
+ def validate(self):
+ """Force revalidation, independent of the conditions specified
+ by the validate option. Returns 0 if validation fails, 1 if it
+ succeeds. Sets or clears the invalid state accordingly."""
+ return self.tk.call(self._w, "validate")
+
+
+class Combobox(Entry):
+ """Ttk Combobox widget combines a text field with a pop-down list of
+ values."""
+
+ def __init__(self, master=None, cnf={}, **kw):
+ """Construct a Ttk Combobox widget with the parent master.
+
+ STANDARD OPTIONS
+
+ class, cursor, style, takefocus
+
+ WIDGET-SPECIFIC OPTIONS
+
+ exportselection, justify, height, postcommand, state,
+ textvariable, values, width
+ """
+ Widget.__init__(self, master, "ttk::combobox", cnf, kw)
+
+
+ def current(self, newindex=None):
+ """If newindex is supplied, sets the combobox value to the element
+ at position newindex in the list of values. Otherwise, returns
+ the index of the current value in the list of values or - 1
+ if the current value does not appear in the list."""
+ return self.tk.call(self._w, "current", newindex)
+
+
+ def set(self, value):
+ """Sets the value of the combobox to value."""
+ self.tk.call(self._w, "set", value)
+
+
+class Frame(Widget):
+ """Ttk Frame widget is a container, used to group other widgets
+ together."""
+
+ def __init__(self, master=None, cnf={}, **kw):
+ """Construct a Ttk Frame with parent master.
+
+ STANDARD OPTIONS
+
+ class, cursor, style, takefocus
+
+ WIDGET-SPECIFIC OPTIONS
+
+ borderwidth, relief, padding, width, height
+ """
+ Widget.__init__(self, master, "ttk::frame", cnf, kw)
+
+
+class Label(Widget):
+ """Ttk Label widget displays a textual label and/or image."""
+
+ def __init__(self, master=None, cnf={}, **kw):
+ """Construct a Ttk Label with parent master.
+
+ STANDARD OPTIONS
+
+ class, compound, cursor, image, style, takefocus, text,
+ textvariable, underline, width
+
+ WIDGET-SPECIFIC OPTIONS
+
+ anchor, background, font, foreground, justify, padding,
+ relief, text, wraplength
+ """
+ Widget.__init__(self, master, "ttk::label", cnf, kw)
Added: sandbox/trunk/ttk-gsoc/samples/combo_themes.py
==============================================================================
--- (empty file)
+++ sandbox/trunk/ttk-gsoc/samples/combo_themes.py Thu Apr 24 17:52:14 2008
@@ -0,0 +1,48 @@
+"""Ttk Theme Selector.
+
+Although it is a theme selector, you won't notice many changes since
+there is only a combobox and a frame around.
+"""
+import Ttk
+
+class App(Ttk.Frame):
+ def __init__(self):
+ Ttk.Frame.__init__(self)
+ self._setup_widgets()
+
+ def _change_theme(self, event):
+ if event.widget.current(): # value #0 is not a theme
+ newtheme = event.widget.get()
+ # change to the new theme and refresh all the widgets
+ self.theme_use(newtheme)
+
+ def _setup_widgets(self):
+ # XXX Not how we have to convert from tuple to list (to add a new
+ # element) and then convert to tuple again so Combobox displays
+ # it correctly. This shouldn't be needed, and I will see what
+ # can be done towards this.
+ themes = list(self.theme_names())
+ themes.insert(0, "Pick a theme")
+ # Create a readonly Combobox which will display 4 values at max,
+ # which will cause it to create a scrollbar if there are more
+ # than 4 values in total.
+ themes_combo = Ttk.Combobox(self, values=tuple(themes),
+ state="readonly", height=4)
+ themes_combo.set(themes[0]) # sets the combobox value to "Pick a theme"
+ # Combobox widget generates a <<ComboboxSelected>> virtual event
+ # when the user selects an element. This event is generated after
+ # the listbox is unposted (after you select an item, the combobox's
+ # listbox disappears, then it is said that listbox is now unposted).
+ themes_combo.bind("<<ComboboxSelected>>", self._change_theme)
+ themes_combo.pack(fill='x')
+
+ self.pack(fill='both', expand=1)
+
+
+def main():
+ app = App()
+ app.master.title("Ttk Combobox")
+ app.mainloop()
+
+if __name__ == "__main__":
+ main()
Added: sandbox/trunk/ttk-gsoc/samples/theme_selector.py
==============================================================================
--- (empty file)
+++ sandbox/trunk/ttk-gsoc/samples/theme_selector.py Thu Apr 24 17:52:14 2008
@@ -0,0 +1,60 @@
+"""Ttk Theme Selector v2.
+
+This is an improvement from the other theme selector (themes_combo.py)
+since now you can notice theme changes in Ttk Ttk Combobox, Ttk Frame,
+Ttk Label and Ttk Button.
+"""
+import Tkinter
+import Ttk
+
+class App(Ttk.Frame):
+ def __init__(self):
+ Ttk.Frame.__init__(self, borderwidth=3)
+
+ # XXX Ideally I wouldn't want to create a Tkinter.IntVar to make
+ # it work with Checkbutton variable option.
+ self.theme_autochange = Tkinter.IntVar(self, 0)
+ self._setup_widgets()
+
+ def _change_theme(self):
+ self.theme_use(self.themes_combo.get())
+
+ def _theme_sel_changed(self, widget):
+ if self.theme_autochange.get():
+ self._change_theme()
+
+ def _setup_widgets(self):
+
+ themes_lbl = Ttk.Label(self, text="Themes")
+
+ themes = self.theme_names()
+ self.themes_combo = Ttk.Combobox(self, values=themes, state="readonly")
+ self.themes_combo.set(themes[0])
+ self.themes_combo.bind("<<ComboboxSelected>>", self._theme_sel_changed)
+
+ change_btn = Ttk.Button(self, text='Change Theme',
+ command=self._change_theme) # XXX how can I set Ttk Button height?
+
+ theme_change_checkbtn = Ttk.Checkbutton(self,
+ text="Change themes when combobox item is activated",
+ variable=self.theme_autochange)
+
+ themes_lbl.grid(ipadx=6, sticky="w")
+ self.themes_combo.grid(row=0, column=1, padx=6, sticky="ew")
+ change_btn.grid(row=0, column=2, padx=6, sticky="e")
+ theme_change_checkbtn.grid(row=1, columnspan=3, sticky="w", pady=6)
+
+ top = self.winfo_toplevel()
+ top.rowconfigure(0, weight=1)
+ top.columnconfigure(0, weight=1)
+ self.columnconfigure(1, weight=1)
+ self.grid(row=0, column=0, sticky="nsew", columnspan=3, rowspan=2)
+
+
+def main():
+ app = App()
+ app.master.title("Theme Selector")
+ app.mainloop()
+
+if __name__ == "__main__":
+ main()
More information about the Python-checkins
mailing list