Owner-Draw Control Example: A Color Table Generator
In creating a product for a client, we needed to show a gradation of color to represent confidence intervals in an audio spectral analysis (when the product is released, this page will show an example of the usage of such a table, but I can't show it right now). The idea is that colors would be more intense at the high-confidence-level analysis level, and fade to white at the zero-confidence level. The problem was to get a nice gradation that worked at different resolutions, and also deal with the fact that the eye's response is somewhat nonlinear. I did not favor typing in a table and experimenting "by hand" and the idea that I would have to use something like PowerPoint or Corel PhotoPaint to create this, and hand-translate to C/C++ did not appeal either. So I wrote a little utility program that could create and read RGB declarations suitable for inclusion in a C/C++ source file.
After having created it, I cleaned up the code a bit and decided to publish it as an example of owner-draw controls. One of the controls, the owner-draw button, is actually detailed in a companion essay on A Better Bitmap Button. The other control, an owner-draw ListBox, appears in another guise in my essay on A Logging ListBox Control.
The ComboBox is interesting in that it is owner-draw with LBS_HASSTRINGS whereas the ListBox is owner-draw without LBS_HASSTRINGS, so two different styles can be studied.
An example of the control is shown below.
Note that the selection highlighting in the ListBox does not extend across the entire entry (which would not make sense, given the desire to show a color), and the selection highlight is grayed out because the ListBox does not currently have the focus. An array of buttons allows immediate selection of common R, G and B values. In the ListBox, the only value stored is the COLORREF value and the string and color are generated at draw time; in the ComboBox, the ItemData stores the COLORREF and the string value stores the name, but the color swatch and color values are generated at draw time. The sample color swatch area represents a simple CStatic and the color is drawn via a simple OnEraseBkgnd handler.
Since this was originally constructed as a Quick & Dirty solution to a specific problem, I did not not apply all my standard production-quality techniques (such as keeping all English-language strings in the STRINGTABLE) so it is not representative of what I consider customer-deliverable code, but it is a close approximation.
I added the complete set of HTML color values, from the HTML documentation. These colors have a "*" following their names. To get the actual HTML name, change the name to all lower-case and remove spaces.
I had a situation in which I needed to read and display the color table information from bitmap files, specifically .bmp and .gif files. So I extended the project. By opening a graphics file, its color table can be extracted and shown in the ListBox. The color table can be written out as a text file containing RGB directives, or it can be viewed as a matrix of colors. There is a new View menu item that will bring up a dialog of the form
By placing the mouse over a color square, its color will be decoded. The color map displayed can be copied to the clipboard so it can be pasted into documentation (such as documentation discussing color tables). The aspect ratio of the table can be changed. Note that a color table typically contains 256 elements (for 8-bit paletted color), 16 elements (for 4-bit paletted color) or 2 elements (for 1-bit color), but in fact a color table can be any size, indicating that there would be no indices in the file for the unused colors. The initial aspect ratio of the table is set heuristically (to the square root of the number of entries, set to the next-higher integer value), but to create an optimum display the aspect ratio can be adjusted with the spin buttons. Also, the size of the blocks can be adjusted to get optimum appearance in the documentation. Here is an example in which there were three colors in the color map. Note that there is an attempt to show it as 2x2, but the unused section is marked off with a hatched pattern.
This is also a useful exercise for those who want to study it on mouse reporting, mouse tracking, the use of WM_MOUSELEAVE, how to handle interacting events on a dialog (changing one edit control triggers a change in the other, but a change in that one triggers a change in its companion, so how to prevent infinite recursion?), and menu enabling in a dialog-based app. It also shows how to read .bmp and .gif (GIF87a and GIF89a format) files, at least as far as reading their color tables. It illustrates techniques such as resizing the dialog to fit the size of its displayed information as the information itself changes size. Cute techniques like how to intercept WM_NCHITTEST and limit resizing to vertical are also illustrated.
|28-Dec-07||#001 Added ability to read color table from paletted bmp or gif file|
|#002 Added standard HTML colors to table|
|#003 Create color table display swatch|
|#004 Support vertical-only resizing of window|
The views expressed in these essays are those of the author, and in no way represent, nor are they endorsed by, Microsoft.