This methods creates and grids all the widgets. For the grid
plan, refer to Section 16, “
class ColorReadout: Text and background color
# - - - C o l o r R e a d o u t . _ _ c r e a t e W i d g e t s def __createWidgets ( self ): """Create and grid all internal widgets. """
The first row contains only a label
that helps the user interpret the background and text colors
that appear aligned below it.
#-- 1 -- # [ self.__rgbLabel := a new Label added and gridded ] self.__rgbLabel = Label ( self, font=MONO_FONT, text="#RRGGBB" ) rowx = 0 self.__rgbLabel.grid ( row=rowx, column=1, sticky=E+W )
The second row contains the radiobutton and readout for the background color.
#-- 2 -- # [ self := self with a new Radiobutton widget that sets # self.__isTextVar to 0 and calls self.__radioHandler # when the radiobutton is changed # self.__bgRadio := that Radiobutton widget ] self.__bgRadio = Radiobutton ( self, command=self.__radioHandler, font=BUTTON_FONT, text="Background color", value=0, variable=self.__isTextVar ) rowx += 1 self.__bgRadio.grid ( row=rowx, column=0, sticky=W )
It might seem logical to use a
Label widget to
display color names, but they have one drawback: the user can't
use the mouse to cut the color name for pasting elsewhere.
Consequently, we use an
Entry widget. Here are
some of the less obvious options, and why we use them:
Make the labels look like they are sticking up. Use a four-pixel border to give some space for this 3-d effect.
Allow the user to cut text from this widget.
We don't want the user to be able to change the text displayed here; this option prevents the tab key from moving the input focus through this widget.
#-- 3 -- # [ self.__bgColorName := a new Entry whose text is # linked to self.__bgColorVar ] self.__bgColorName = Entry ( self, exportselection=1, takefocus=0, width=7, relief=RAISED, bd=4, bg="white", font=MONO_FONT, textvariable=self.__bgColorVar ) self.__bgColorName.grid ( row=rowx, column=1, padx=4, sticky=W )
The next row is quite similar to the previous row, but it is for the text color.
#-- 4 -- # [ self := self with a new Radiobutton widget that sets # self.__isTextVar to 1 and calls self.__radioHandler # when the radiobutton is changed # self.__textRadio := that Radiobutton widget ] self.__textRadio = Radiobutton ( self, command=self.__radioHandler, font=BUTTON_FONT, text="Text color", value=1, variable=self.__isTextVar ) rowx += 1 self.__textRadio.grid ( row=rowx, column=0, sticky=W ) #-- 5 -- # [ self.__textColorName := a new Entry whose text is # linked to self.__textColorVar ] self.__textColorName = Entry ( self, exportselection=1, takefocus=0, width=7, relief=RAISED, bd=4, bg="white", font=MONO_FONT, textvariable=self.__textColorVar ) self.__textColorName.grid ( row=rowx, column=1, padx=4, sticky=W )
There is a drawback to using an
widget to display the color values: the user can then
edit the displayed values, which would mean they no
longer reflect the actual color values. One trick we
tried is to set
state=DISABLED in both
Entry widgets. This does a fine job of
preventing the user from changing the value, and in an
older Tkinter version, the fix worked. However, in
a newer Tkinter install, it is now impossible to use
cut-and-paste on a disabled widget.
The solution is to bind all keyboard events to a little
handler called Section 16.9, “
user modification of the
This event handler rewrites the values of both the names
to keep them consistent with the internal colors. Here
is the code that sets up that event binding.
#-- 6 -- # [ self.__bgColorName := self.__bgColorName set up so # that any user keypresses cause self.__bgColorVar # to be set to str(self.__bgColor) # self.__textColorName := self.__textColorName set up so # that any user keypresses cause self.__textColorVar # to be set to str(self.__textColor) ] self.__bgColorName.bind ( "<Any-KeyRelease>", self.__fixNames ) self.__textColorName.bind ( "<Any-KeyRelease>", self.__fixNames )