Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

TCX Owner Draw Engine

0.00/5 (No votes)
1 Dec 1999 1  
A class that helps writing owner-drawn controls with text formatting capabilities

Sample Image - TcxOde.gif

Here, I present a class that helps writing Owner Draw Controls with basic - although cute - text formatting capabilities.

The CTcxOwnerDrawEngine class is not a control class by its own, or even a CWnd derived class. As a matter of fact, its objects work as aggregateable members of Owner Draw Controls objects. By instantiating a CTcxOwnerDrawEngine as a member object, such controls can rely on delegation to let the engine take care of the complex draw and format operations.

All we have to do is to redirect the control's DrawItem method to the CTcxOwnerDrawEngine::DrawItem method, providing it with the draw item data (DRAWITEMSTRUCT), and the item's tagged text string.

The tagged item's string describes both the text and the format, pretty much as other tagged syntaxes do. Of course, it's not so powerful as HTML or Rich Text Format. But, for the basic stuff, it's pretty good.

Just to make it clear now, so I won't disappoint you later: at this version, it's not possible to mix different font typefaces or font sizes. However, you still can change the font color and any of its bold, italic or underline attributes (in any combination).

For a glance, the figure that opens this article is a snapshot of the TcxOde Demo Application screen, taken after the following tagged items were entered - you must enter line by line.

<0><-><j><#1010>Table<10>
<#1000><0><|><j>Group A<5><|><j>Group B<10><|>
<#1000><0><|><-><j>Col X<1><|><-><j>Col
Y<2><|><-><j>Col Z<5><|><-><j>
Col W<6><|><-><j>Col T<10><|>
<0><|> <i0> <20> Thales <1><|><j><j><#5>10 <#><2><|><#1><b10><#><5><|>---<6><|>---<10><|>
<0><|> <i0><i1><i2> <20> Ricardo <1><|><j><j><#5>100 <#><2><|><#1><b100><#><5><|>---<6><|>---<10><|>
<0><|> <i0> <20> Pacheco <1><|><j><j><#5>20 <#><2><|><#1><b20><#><5><|>---<6><|>---<10><|>
<0><|> <i0><i1> <20> Eloy <1><|><j><j><#5>50 <#><2><|><#1><b50><#><5><|>---<6><|>---<10><|>
<0><|> <i2> <20> Marcio <1><|><j><j><#5>3 <#><2><|><#1><b3><#><5><|>---<6><|>---<10><|>
<0><|><1><|><2><|><5><|><6><|><10><|>
<0><-><|><1><-><|><2><-><|
><5><-><|><6><-><|><10><|>
<0><-><|><#1000><j><j> Total<#>
<1><-><j><j><-><#5>11111 <#><2><|>

The TcxOde Demo Application uses the CTcxOdeListBox, which is a CTcxOwnerDrawEngine equipped MFC Owner Draw CListBox.

Tags Overview

Here is a description of each existing tag.

  • <#n> - Select Style

    This tag selects the style n for the subsequent drawing, where n is a decimal identifier from 0 up to 4294967294. Each style has a text color and a font attribute (either bold, italic, underline or any combination of those). At this version (and probably this is the last one), it's not possible to change the font size, neither the font typeface.

    Styles are independently configurable through the CTcxOwnerDrawEngine::SetStyle member function.

    I designed it to use externally configurable styles, rather than putting direct tags to select font attributes and text colors, because I think styles are more abstract. Therefore, you can change one style properties and all the affected items will be changed automatically, without having to be reformatted and reinserted in the control.

    The selected style won't persist from one item to other. Every time the engine starts drawing a new item, it resets to the default style.

    If a style doesn't exist (it was not configured with CTcxOwnerDrawEngine::SetStyle), the engine keeps using the current style.

    You can use sparse style IDs (e.g. 1015 and 3). Internally, the engine keeps them in an ordered CArray and uses binary search (which, for this particular purpose, has better performance than the CMap, for both memory and speed).

  • <#> - Select Default Style

    The default style is basically the style of the DC that's provided for CTcxOwnerDrawEngine::DrawItem.

  • <n> - Tab Stop

    This tag aligns the current draw position with the tab stop n, where n is a decimal identifier from 0 up to 4294967294.

    Well, at first, it's a normal tab stop, but there're three major differences:

    • It has an ID. Therefore, you always know to which tab stop you're going to advance the drawing position. In an ID-less tab stop List Box, for instance, if the drawing position is already beyond the desired tab stop (the previous text was too long), it'll advance to the next tab stop - if any -, and the item will show unaligned.

    • Again, it has an ID. Another advantage of labeled tab stops is they affect only the items that refer to them. Therefore, you might have different groups of items, each one using a separate group of tab stops, and one will not get in the way of the other.

    • The engine automatically resizes them, so the distance between any two different tab stops is always enough to fit any text that happen to be between them. It makes the tag useful to create tables.

  • <j> or <J> - Justification

    This tag changes the justification alignment from left to center, and from center to right, between two consecutive tab marks.

    The engine stars aligning text to the left. If it finds this tag once, the subsequent output will be aligned to the center, and, if it finds this tag twice or more, the subsequent output will be aligned to the right.

    For instance, the following tagged text items will produce the next figure's output.

    Left <j> Center <j> Right
    Just Left
    <j> Just Center
    Left and... <j><j> Right
    

    Figure 2

    Since the output is once aligned to the right, extra Justification tags would have no effect. However, do note that the Tab Stop tag will reset the alignment back to the left.

  • <in> or <In> - Icon Tag

    Yes, you can attach a CImageList to the engine (CTcxOwnerDrawEngine::AttachImageList) and instruct it to draw icons, using this tag. Just give the icon index.

  • <-> - Bottom Horizontal Border

    This tag instructs the engine to draw a bottom border (a 1 pixel horizontal line) between the current tab stops, using the current style color.

  • <|> - Vertical Border

    This tag instructs the engine to draw a vertical border (a 1 pixel vertical line) at the current drawing position.

  • <bw> or <Bw> - Bar

    This tag instructs the engine to draw a bar w pixels wide. It advances the current drawing position of w pixels to the right. The bar is painted with the current style's text color.

  • << - Less Than Character

    This tag draws the '<' character.

  • >> - Greater Than Character

    This tag draws the '>' character.

CTcxOwnerDrawEngine Class Members

CTcxOwnerDrawEngine( void )

Constructs a CTcxOwnerDrawEngine object. You'll generally construct it as a member of a Owner Draw Control object class (for an example, see demo's CTcxOdeListBox).

~CTcxOwnerDrawEngine( void )

Destructs a CTcxOwnerDrawEngine object. Do note that the destructor is not virtual. Thus the object is not intended to be used as a base class, but as an aggregated object.

void SetStyle( DWORD dwStyleId, COLORREF clrText, BOOL bBold, BOOL bItalic, BOOL bUnderline )

Sets the attributes of the Style identified by dwStyleId.

CImageList* AttachImageList( CImageList* pImgList )

Attach a Image List object to the CTcxOwnerDrawEngine. The Image List object must not be destructed until it's either detached or the CTcxOwnerDrawEngine object is destructed. The CTcxOwnerDrawEngine only refers to the Image List object, and has no control on its lifetime. The function returns the previous attached Image List object, or NULL, if there wasn't any previous attachment.

CImageList* DetachImageList( void )

Detaches the current Image List object. Returns the pointer to the just detached Image List, or NULL if there's no Image List currently attached.

void DrawItem( LPDRAWITEMSTRUCT pDrw, LPCTSTR pszText )

Draws the tagged text given by pszText in the Owner Draw Item context given by pDrw.

BOOL InvalidateIsRequired( void )

If the last DrawItem operation has moved any Tab Stop guideline, this function returns TRUE. It indicates to a multi-item container control (e.g. List Box) that all the other visible items should be redraw to reflect the new alignment. The control can do this by invalidating its client area (see demo's CTcxOdeListBox).

void DeleteFonts( void )

Deletes all cached fonts. It's done automatically when the object is destructed. Use this to "clean-up" the engine's cache when some styles were modified.

void DeleteTabs( void )

Resets all the Tab Stop guidelines. Use this to "clean-up" the engine's tab stops after an item is removed.

int MaxWidth( void )

Returns the width of the largest item that has been already drawn by the engine. The owner control can use this value to resize its horizontal extension or scroll bar, so all items will be fully visible (see demo's CTcxOdeListBox).

void SetMinimumWidth( int cx )

Sets the minimum item width, in pixels. The engine might draw items wider, but not narrower than this size. This forces the engine to expand items with center and right elements, even if the item could be drawn with less space.

TcxOde Demo Application Features

The demo application is just a dialog box with an edit box and a CTcxOdeListBox. The list box's stamina is a CTcxOwnerDrawEngine object. The edit box is just for entering tagged items strings in the list box. So, just type the text in the edit box and press <return>. You can also delete an item by selecting it and pressing <del>. The dialog box is resizeable.

In the demo application, I use the following Style ID pattern: biuC.

Where b, i and u are the flags for font attributes bold, italic and underline. These flags can be either 1 (on) or 0 (off). And C is a color index, being 0 black, 1 light red, 2 light green, 3 light blue, 4 dark red, 5 dark green, and 6 dark blue.

Therefore, such a tag as <#1003> will activate the blue bold font style.

But do note that you can program whatever combination you want.

Files to Include

To use the CTcxOwnerDrawEngine, the only files you must include in your project are:

  • TcxOde.h
  • TcxOde.cpp

Another class that's ready and easy to use, although it's not the focus of this article, is the CTcxOdeListBox. You don't need to use it in order to use the engine. This is a MFC Owner Draw List Box. To use it in a Dialog Box, in the Dialog's template create an Owner Draw List Box with the following attributes: single selection, owner draw fixed, has strings. Then, create a CTcxOdeListBox object as a member of the Dialog's class, and use it to subclass the List Box. The files you'll need are:

  • TcxOde.h
  • TcxOde.cpp
  • TcxOdeListBox.h
  • TcxOdeListBox.cpp

License

This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.

A list of licenses authors might use can be found here.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here