]> granicus.if.org Git - python/commitdiff
Many changes to support a second mode of operation. Pynche can now be
authorBarry Warsaw <barry@python.org>
Thu, 22 Oct 1998 03:25:59 +0000 (03:25 +0000)
committerBarry Warsaw <barry@python.org>
Thu, 22 Oct 1998 03:25:59 +0000 (03:25 +0000)
run either as a standalone application (by running pynche or
pynche.pyw), or as a modal dialog inside another application.  This
can be done by importing pyColorChooser and running askcolor().  The
API for this is the same as the tkColorChooser.askcolor() API, namely:

    When `Okay' is hit, askcolor() returns ((r, g, b), "name").  When
    `Cancel' is hit, askcolor() returns (None, None).

Note the following differences:

    1. pyColorChooser.askcolor() takes an optional keyword `master'
       which if set tells Pynche to run as a modal dialog.  `master'
       is a Tkinter parent window.  Without the `master' keyword
       Pynche runs standalone.

    2. in pyColorChooser.askcolor() will return a Tk/X11 color name as
       "name" if there is an exact match, otherwise it will return a
       color spec, e.g. "#rrggbb".  tkColorChooser can't return a
       color name.

There are also some UI differences when running standalone vs. modal.
When modal, there is no "File" menu, but instead there are "Okay" and
"Cancel" buttons.

The implementation of all this is a bit of a hack, but it seems to
work moderately well.  I'm not guaranteeing the pyColorChooser.Chooser
class has the same semantics as the tkColorChooser.Chooser class.

Tools/pynche/ChipViewer.py
Tools/pynche/DetailsViewer.py
Tools/pynche/ListViewer.py
Tools/pynche/Main.py
Tools/pynche/PyncheWidget.py
Tools/pynche/StripViewer.py
Tools/pynche/Switchboard.py
Tools/pynche/TextViewer.py
Tools/pynche/TypeinViewer.py
Tools/pynche/pyColorChooser.py [new file with mode: 0644]

index fbf9aad7d5dc692f51f760da7f56acbecc6d30d6..5bd0bdfa02f0c7793384205caf170a01d46dd925 100644 (file)
@@ -23,7 +23,7 @@ class ChipWidget:
     _HEIGHT = 80
 
     def __init__(self,
-                 parent = None,
+                 master = None,
                  width  = _WIDTH,
                  height = _HEIGHT,
                  text   = 'Color',
@@ -31,16 +31,16 @@ class ChipWidget:
                  presscmd   = None,
                  releasecmd = None):
         # create the text label
-        self.__label = Label(parent, text=text)
+        self.__label = Label(master, text=text)
         self.__label.grid(row=0, column=0)
         # create the color chip, implemented as a frame
-        self.__chip = Frame(parent, relief=RAISED, borderwidth=2,
+        self.__chip = Frame(master, relief=RAISED, borderwidth=2,
                             width=width,
                             height=height,
                             background=initialcolor)
         self.__chip.grid(row=1, column=0)
         # create the color name, ctor argument must be a string
-        self.__name = Label(parent, text=initialcolor)
+        self.__name = Label(master, text=initialcolor)
         self.__name.grid(row=2, column=0)
         #
         # set bindings
@@ -65,10 +65,10 @@ class ChipWidget:
 
 \f
 class ChipViewer:
-    def __init__(self, switchboard, parent=None):
+    def __init__(self, switchboard, master=None):
         self.__sb = switchboard
-        self.__frame = Frame(parent) #, relief=GROOVE, borderwidth=2)
-        self.__frame.grid(row=3, column=0)
+        self.__frame = Frame(master, relief=RAISED, borderwidth=1)
+        self.__frame.grid(row=3, column=0, ipadx=5)
         # create the chip that will display the currently selected color
         # exactly
         self.__sframe = Frame(self.__frame)
@@ -81,11 +81,6 @@ class ChipViewer:
         self.__nearest = ChipWidget(self.__nframe, text='Nearest',
                                     presscmd = self.__buttonpress,
                                     releasecmd = self.__buttonrelease)
-        self.__div = Frame(self.__frame,
-                           width=2,
-                           borderwidth=2,
-                           relief=RAISED)
-        self.__div.grid(row=0, column=2, sticky='NS', padx=5)
 
     def update_yourself(self, red, green, blue):
         # TBD: should exactname default to X11 color name if their is an exact
@@ -110,6 +105,3 @@ class ChipViewer:
         colorname = self.__nearest.get_color()
         red, green, blue = self.__sb.colordb().find_byname(colorname)
         self.__sb.update_views(red, green, blue)
-
-    def save_options(self, optiondb):
-        pass
index da9bbf9616db854b1b627a8b4c935d3f7c89524d..69964236f9bf915ada8069401a4b5706ea44de7c 100644 (file)
@@ -61,19 +61,19 @@ GRAV = 'Squash'
 
 \f
 class DetailsViewer:
-    def __init__(self, switchboard, parent=None):
+    def __init__(self, switchboard, master=None):
         self.__sb = switchboard
         optiondb = switchboard.optiondb()
         self.__red, self.__green, self.__blue = switchboard.current_rgb()
         # GUI
-        root = self.__root = Toplevel(parent, class_='Pynche')
-        root.protocol('WM_DELETE_WINDOW', self.__withdraw)
+        root = self.__root = Toplevel(master, class_='Pynche')
+        root.protocol('WM_DELETE_WINDOW', self.withdraw)
         root.title('Pynche Details Window')
         root.iconname('Pynche Details Window')
         root.bind('<Alt-q>', self.__quit)
         root.bind('<Alt-Q>', self.__quit)
-        root.bind('<Alt-w>', self.__withdraw)
-        root.bind('<Alt-W>', self.__withdraw)
+        root.bind('<Alt-w>', self.withdraw)
+        root.bind('<Alt-W>', self.withdraw)
         # accelerators
         root.bind('<KeyPress-Left>', self.__minus1)
         root.bind('<KeyPress-Right>', self.__plus1)
@@ -158,7 +158,7 @@ class DetailsViewer:
     def __quit(self, event=None):
         self.__root.quit()
 
-    def __withdraw(self, event=None):
+    def withdraw(self, event=None):
         self.__root.withdraw()
 
     def deiconify(self, event=None):
index 9ba2a5365c848a74725a6a1eafa325d433edefab..eb43a928607424c67cdec3180616002febf773dd 100644 (file)
@@ -19,20 +19,20 @@ from Tkinter import *
 import ColorDB
 
 class ListViewer:
-    def __init__(self, switchboard, parent=None):
+    def __init__(self, switchboard, master=None):
         self.__sb = switchboard
         optiondb = switchboard.optiondb()
         self.__lastbox = None
         self.__dontcenter = 0
         # GUI
-        root = self.__root = Toplevel(parent, class_='Pynche')
-        root.protocol('WM_DELETE_WINDOW', self.__withdraw)
+        root = self.__root = Toplevel(master, class_='Pynche')
+        root.protocol('WM_DELETE_WINDOW', self.withdraw)
         root.title('Pynche Color List')
         root.iconname('Pynche Color List')
         root.bind('<Alt-q>', self.__quit)
         root.bind('<Alt-Q>', self.__quit)
-        root.bind('<Alt-w>', self.__withdraw)
-        root.bind('<Alt-W>', self.__withdraw)
+        root.bind('<Alt-w>', self.withdraw)
+        root.bind('<Alt-W>', self.withdraw)
         #
         # create the canvas which holds everything, and its scrollbar
         #
@@ -125,7 +125,7 @@ class ListViewer:
     def __quit(self, event=None):
         self.__root.quit()
 
-    def __withdraw(self, event=None):
+    def withdraw(self, event=None):
         self.__root.withdraw()
 
     def deiconify(self, event=None):
index bb5329e751d02fbc4629ef8c8671f4c5ab4ca9f7..f266a8d184fec2e0ebca3c1a66e31a0b6e5b0bfc 100644 (file)
@@ -104,34 +104,7 @@ def initial_color(s, colordb):
 
 
 \f
-def main():
-    try:
-       opts, args = getopt.getopt(
-            sys.argv[1:],
-            'hd:i:X',
-            ['database=', 'initfile=', 'ignore', 'help'])
-    except getopt.error, msg:
-       usage(1, msg)
-
-    if len(args) == 0:
-        initialcolor = None
-    elif len(args) == 1:
-        initialcolor = args[0]
-    else:
-       usage(1)
-
-    ignore = 0
-    initfile = os.path.expanduser('~/.pynche')
-    for opt, arg in opts:
-       if opt in ('-h', '--help'):
-           usage(0)
-       elif opt in ('-d', '--database'):
-           RGB_TXT.insert(0, arg)
-        elif opt in ('-X', '--ignore'):
-            ignore = 1
-        elif opt in ('-i', '--initfile'):
-            initfile = arg
-
+def build(master=None, initialcolor=None, initfile=None, ignore=None):
     # create the windows and go
     for f in RGB_TXT:
        try:
@@ -147,12 +120,12 @@ def main():
     s = Switchboard(colordb, not ignore and initfile)
 
     # create the application window decorations
-    app = PyncheWidget(__version__, s)
-    parent = app.parent()
+    app = PyncheWidget(__version__, s, master=master)
+    w = app.window()
 
-    s.add_view(StripViewer(s, parent))
-    s.add_view(ChipViewer(s, parent))
-    s.add_view(TypeinViewer(s, parent))
+    s.add_view(StripViewer(s, w))
+    s.add_view(ChipViewer(s, w))
+    s.add_view(TypeinViewer(s, w))
 
     # get the initial color as components and set the color on all views.  if
     # there was no initial color given on the command line, use the one that's 
@@ -168,15 +141,48 @@ def main():
     else:
         red, green, blue = initial_color(initialcolor, colordb)
     s.update_views(red, green, blue)
+    return app, s
+
 
+def run(app, s):
     try:
        app.start()
     except KeyboardInterrupt:
        pass
-
     # save the option database
-    s.save_views(initfile)
+    s.save_views()
+
+
+\f
+def main():
+    try:
+       opts, args = getopt.getopt(
+            sys.argv[1:],
+            'hd:i:X',
+            ['database=', 'initfile=', 'ignore', 'help'])
+    except getopt.error, msg:
+       usage(1, msg)
+
+    if len(args) == 0:
+        initialcolor = None
+    elif len(args) == 1:
+        initialcolor = args[0]
+    else:
+       usage(1)
+
+    ignore = 0
+    initfile = os.path.expanduser('~/.pynche')
+    for opt, arg in opts:
+       if opt in ('-h', '--help'):
+           usage(0)
+       elif opt in ('-d', '--database'):
+           RGB_TXT.insert(0, arg)
+        elif opt in ('-X', '--ignore'):
+            ignore = 1
+        elif opt in ('-i', '--initfile'):
+            initfile = arg
 
+    run()
 
 \f
 if __name__ == '__main__':
index 4052357a0d7ec6d52c70e7708966b2e9e72e7d73..fcabd240eaaec4f448cf444d4be44541874d3611 100644 (file)
@@ -13,36 +13,46 @@ KEEPALIVE_TIMER = 500
 
 \f
 class PyncheWidget:
-    def __init__(self, version, switchboard):
+    def __init__(self, version, switchboard, master=None):
         self.__sb = switchboard
         self.__version = version
         self.__textwin = None
         self.__listwin = None
         self.__detailswin = None
-        #
-        # Is there already a default root for Tk, say because we're running
-        # under Guido's IDE? :-) Two conditions say no, either the import
-        # fails or _default_root is None.
-        tkroot = None
-        try:
-            from Tkinter import _default_root
-            tkroot = self.__tkroot = _default_root
-        except ImportError:
-            pass
-        if not tkroot:
-            tkroot = self.__tkroot = Tk(className='Pynche')
-        # but this isn't our top level widget, so make it invisible
-        tkroot.withdraw()
+        modal = self.__modal = not not master
+        # If a master was given, we are running as a modal dialog servant to
+        # some other application.  We rearrange our UI in this case (there's
+        # no File menu and we get `Okay' and `Cancel' buttons), and we do a
+        # grab_set() to make ourselves modal
+        if modal:
+            self.__tkroot = tkroot = Toplevel(master, class_='Pynche')
+            tkroot.grab_set()
+            tkroot.withdraw()
+        else:
+            # Is there already a default root for Tk, say because we're
+            # running under Guido's IDE? :-) Two conditions say no, either the
+            # import fails or _default_root is None.
+            tkroot = None
+            try:
+                from Tkinter import _default_root
+                tkroot = self.__tkroot = _default_root
+            except ImportError:
+                pass
+            if not tkroot:
+                tkroot = self.__tkroot = Tk(className='Pynche')
+            # but this isn't our top level widget, so make it invisible
+            tkroot.withdraw()
         # create the menubar
         menubar = self.__menubar = Menu(tkroot)
         #
         # File menu
         #
-        filemenu = self.__filemenu = Menu(menubar, tearoff=0)
-        filemenu.add_command(label='Quit',
-                             command=self.__quit,
-                             accelerator='Alt-Q',
-                             underline=0)
+        if not modal:
+            filemenu = self.__filemenu = Menu(menubar, tearoff=0)
+            filemenu.add_command(label='Quit',
+                                 command=self.__quit,
+                                 accelerator='Alt-Q',
+                                 underline=0)
         #
         # View menu
         #
@@ -66,9 +76,10 @@ class PyncheWidget:
         #
         # Tie them all together
         #
-        menubar.add_cascade(label='File',
-                            menu=filemenu,
-                            underline=0)
+        if not modal:
+            menubar.add_cascade(label='File',
+                                menu=filemenu,
+                                underline=0)
         menubar.add_cascade(label='View',
                             menu=viewmenu,
                             underline=0)
@@ -78,15 +89,44 @@ class PyncheWidget:
 
         # now create the top level window
         root = self.__root = Toplevel(tkroot, class_='Pynche', menu=menubar)
-        root.protocol('WM_DELETE_WINDOW', self.__quit)
+        root.protocol('WM_DELETE_WINDOW',
+                      modal and self.__beep or self.__quit)
         root.title('Pynche %s' % version)
         root.iconname('Pynche')
-        root.tk.createtimerhandler(KEEPALIVE_TIMER, self.__keepalive)
-        root.bind('<Alt-q>', self.__quit)
-        root.bind('<Alt-Q>', self.__quit)
+        # Only bind accelerators for the File->Quit menu item if running as a
+        # standalone app
+        if not modal:
+            root.bind('<Alt-q>', self.__quit)
+            root.bind('<Alt-Q>', self.__quit)
+        else:
+            # We're a modal dialog so we have a new row of buttons
+            bframe = Frame(root, borderwidth=1, relief=RAISED)
+            bframe.grid(row=4, column=0, columnspan=2,
+                        sticky='EW',
+                        ipady=5)
+            okay = Button(bframe,
+                          text='Okay',
+                          command=self.__okay)
+            okay.pack(side=LEFT, expand=1)
+            cancel = Button(bframe,
+                            text='Cancel',
+                            command=self.__cancel)
+            cancel.pack(side=LEFT, expand=1)
 
     def __quit(self, event=None):
-        self.__root.quit()
+        self.__tkroot.quit()
+
+    def __beep(self, event=None):
+        self.__tkroot.beep()
+
+    def __okay(self, event=None):
+        self.__sb.withdraw_views()
+        self.__tkroot.grab_release()
+        self.__quit()
+
+    def __cancel(self, event=None):
+        self.__sb.canceled()
+        self.__okay()
 
     def __keepalive(self):
         # Exercise the Python interpreter regularly so keyboard interrupts get
@@ -94,10 +134,11 @@ class PyncheWidget:
         self.__tkroot.tk.createtimerhandler(KEEPALIVE_TIMER, self.__keepalive)
 
     def start(self):
-        self.__keepalive()
+        if not self.__modal:
+            self.__keepalive()
         self.__tkroot.mainloop()
 
-    def parent(self):
+    def window(self):
         return self.__root
 
     def __popup_about(self, event=None):
@@ -135,3 +176,6 @@ email : bwarsaw@python.org''' % __version__)
             self.__detailswin = DetailsViewer(self.__sb, self.__root)
             self.__sb.add_view(self.__detailswin)
         self.__detailswin.deiconify()
+
+    def withdraw(self):
+        self.__root.withdraw()
index 7bbfcca1f5f9b9ff52d5b906362555aea270bc2e..f085fec1779e1d823135742e8c3986c796e40219 100644 (file)
@@ -147,7 +147,7 @@ class StripWidget:
     _NUMCHIPS = 40
 
     def __init__(self, switchboard,
-                 parent     = None,
+                 master     = None,
                  chipwidth  = _CHIPWIDTH,
                  chipheight = _CHIPHEIGHT,
                  numchips   = _NUMCHIPS,
@@ -171,13 +171,12 @@ class StripWidget:
        canvasheight = chipheight + 43            # TBD: Kludge
 
        # create the canvas and pack it
-       canvas = self.__canvas = Canvas(
-           parent,
-           width=canvaswidth,
-           height=canvasheight,
-##         borderwidth=2,
-##         relief=GROOVE
-           )
+       canvas = self.__canvas = Canvas(master,
+                                        width=canvaswidth,
+                                        height=canvasheight,
+##                                        borderwidth=2,
+##                                        relief=GROOVE
+                                        )
 
        canvas.pack()
        canvas.bind('<ButtonPress-1>', self.__select_chip)
@@ -296,11 +295,11 @@ class StripWidget:
 
 \f
 class StripViewer:
-    def __init__(self, switchboard, parent=None):
+    def __init__(self, switchboard, master=None):
         self.__sb = switchboard
         optiondb = switchboard.optiondb()
-        # create a frame inside the parent
-        self.__frame = Frame(parent) #, relief=GROOVE, borderwidth=2)
+        # create a frame inside the master
+        self.__frame = Frame(master, relief=RAISED, borderwidth=1)
         self.__frame.grid(row=1, column=0, columnspan=2, sticky='EW')
         uwd = self.__uwdvar = BooleanVar()
         uwd.set(optiondb.get('UPWHILEDRAG', 0))
@@ -338,12 +337,6 @@ class StripViewer:
                                  command=self.__togglehex)
         self.__hex.grid(row=1, column=0, sticky=W)
 
-        self.__div = Frame(self.__frame,
-                           height=2,
-                           borderwidth=2,
-                           relief=RAISED)
-        self.__div.pack(expand=1, fill=X)
-
     def update_yourself(self, red, green, blue):
         self.__reds.update_yourself(red, green, blue)
         self.__greens.update_yourself(red, green, blue)
index 7ac3df11b450b2b83761567d65a14be11a4b73d7..d8fd14c9925a5d30a4a213d6f7e8947c07af2f88 100644 (file)
@@ -17,12 +17,14 @@ import marshal
 
 class Switchboard:
     def __init__(self, colordb, initfile):
+        self.__initfile = initfile
         self.__colordb = colordb
         self.__optiondb = {}
         self.__views = []
         self.__red = 0
         self.__green = 0
         self.__blue = 0
+        self.__canceled = 0
         # read the initialization file
         fp = None
         if initfile:
@@ -61,17 +63,18 @@ class Switchboard:
     def optiondb(self):
         return self.__optiondb
 
-    def save_views(self, file):
+    def save_views(self):
         # save the current color
         self.__optiondb['RED'] = self.__red
         self.__optiondb['GREEN'] = self.__green
         self.__optiondb['BLUE'] = self.__blue
         for v in self.__views:
-            v.save_options(self.__optiondb)
+            if hasattr(v, 'save_options'):
+                v.save_options(self.__optiondb)
         fp = None
         try:
             try:
-                fp = open(file, 'w')
+                fp = open(self.__initfile, 'w')
             except IOError:
                 print 'Cannot write options to file:', file
             else:
@@ -79,3 +82,14 @@ class Switchboard:
         finally:
             if fp:
                 fp.close()
+
+    def withdraw_views(self):
+        for v in self.__views:
+            if hasattr(v, 'withdraw'):
+                v.withdraw()
+
+    def canceled(self):
+        self.__canceled = 1
+
+    def canceled_p(self):
+        return self.__canceled
index 7e8cec5c362311fe959ba809019d977ac400978a..a3e9ac52c625c30ced8217bc81c190a475dad7e7 100644 (file)
@@ -19,17 +19,17 @@ from Tkinter import *
 import ColorDB
 
 class TextViewer:
-    def __init__(self, switchboard, parent=None):
+    def __init__(self, switchboard, master=None):
         self.__sb = switchboard
         optiondb = switchboard.optiondb()
-        root = self.__root = Toplevel(parent, class_='Pynche')
-        root.protocol('WM_DELETE_WINDOW', self.__withdraw)
+        root = self.__root = Toplevel(master, class_='Pynche')
+        root.protocol('WM_DELETE_WINDOW', self.withdraw)
         root.title('Pynche Text Window')
         root.iconname('Pynche Text Window')
         root.bind('<Alt-q>', self.__quit)
         root.bind('<Alt-Q>', self.__quit)
-        root.bind('<Alt-w>', self.__withdraw)
-        root.bind('<Alt-W>', self.__withdraw)
+        root.bind('<Alt-w>', self.withdraw)
+        root.bind('<Alt-W>', self.withdraw)
         #
         # create the text widget
         #
@@ -114,7 +114,7 @@ and choosing a color.'''))
     def __quit(self, event=None):
         self.__root.quit()
 
-    def __withdraw(self, event=None):
+    def withdraw(self, event=None):
         self.__root.withdraw()
 
     def deiconify(self, event=None):
index 13cb9c742401d938ffb810cac82850eb6c6e1dd6..d10d2a9c9bd55f9ea8b95af0713804edfdf16ec8 100644 (file)
@@ -17,7 +17,7 @@ import string
 import re
 
 class TypeinViewer:
-    def __init__(self, switchboard, parent=None):
+    def __init__(self, switchboard, master=None):
         # non-gui ivars
         self.__sb = switchboard
         optiondb = switchboard.optiondb()
@@ -26,7 +26,7 @@ class TypeinViewer:
         self.__uwtyping = BooleanVar()
         self.__uwtyping.set(optiondb.get('UPWHILETYPE', 0))
         # create the gui
-        self.__frame = Frame(parent) #, relief=GROOVE, borderwidth=2)
+        self.__frame = Frame(master, relief=RAISED, borderwidth=1)
         self.__frame.grid(row=3, column=1, sticky='NS')
         # Red
         self.__xl = Label(self.__frame, text='Red:')
diff --git a/Tools/pynche/pyColorChooser.py b/Tools/pynche/pyColorChooser.py
new file mode 100644 (file)
index 0000000..f2dc6ac
--- /dev/null
@@ -0,0 +1,87 @@
+"""Color chooser implementing (almost) the tkColorColor interface
+"""
+
+import os
+from PyncheWidget import PyncheWidget
+import Main
+import ColorDB
+
+class Chooser:
+    """Ask for a color"""
+    def __init__(self,
+                 master = None,
+                 initialcolor = None,
+                 databasefile = None,
+                 initfile = None,
+                 ignore = None):
+        self.__master = master
+        self.__initialcolor = initialcolor
+        self.__databasefile = databasefile
+        self.__initfile = initfile or os.path.expanduser('~/.pynche')
+        self.__ignore = ignore
+        self.__pw = None
+
+    def show(self):
+        if not self.__pw:
+            self.__pw, self.__sb = \
+                       Main.build(master = self.__master,
+                                  initialcolor = self.__initialcolor,
+                                  initfile = self.__initfile,
+                                  ignore = self.__ignore)
+        Main.run(self.__pw, self.__sb)
+        rgbtuple = self.__sb.current_rgb()
+        self.__pw.withdraw()
+        # check to see if the cancel button was pushed
+        if self.__sb.canceled_p():
+            return None, None
+        colordb = self.__sb.colordb()
+        # try to return the color name from the database if there is an exact
+        # match, otherwise use the "#rrggbb" spec.  TBD: Forget about color
+        # aliases for now, maybe later we should return these too.
+        try:
+            name = colordb.find_byrgb(rgbtuple)[0]
+        except ColorDB.BadColor:
+            name = ColorDB.triplet_to_rrggbb(rgbtuple)
+        return rgbtuple, name
+
+
+\f
+# convenience stuff
+def askcolor(color = None, **options):
+    """Ask for a color"""
+    return apply(Chooser, (), options).show()
+
+
+\f
+# test stuff
+if __name__ == '__main__':
+    class Tester:
+        def __init__(self):
+            from Tkinter import *
+            self.__root = tk = Tk()
+            b = Button(tk, text='Choose Color...', command=self.__choose)
+            b.pack()
+            self.__l = Label(tk)
+            self.__l.pack()
+            q = Button(tk, text='Quit', command=self.__quit)
+            q.pack()
+
+        def __choose(self, event=None):
+            rgb, name = askcolor(master=self.__root)
+            if rgb is None:
+                text = 'You hit CANCEL!'
+            else:
+                r, g, b = rgb
+                text = 'You picked %s (%3d/%3d/%3d)' % (name, r, g, b)
+            self.__l.configure(text=text)
+
+        def __quit(self, event=None):
+            self.__root.quit()
+
+        def run(self):
+            self.__root.mainloop()
+    t = Tester()
+    t.run()
+    # simpler
+##    print 'color:', askcolor()
+##    print 'color:', askcolor()