Click here to Skip to main content
Click here to Skip to main content

CWnd/WTL based HTML List Control with different row heights

By , 2 May 2006
 

Introduction

As a shareware developer I use a lot of custom controls and stuff to make the application pretty as well as useful. For my last project, I had to build a list control with all sorts of funky stuff happening in the list items and I thought it would be nice to have a list control that could render the individual item's text in HTML.

As we know the changing of row height in CListCtrl is a real pain, funny methods like using large fonts and stuff exist but they are not pretty and largely of no use to me, so I decided to write the whole thing from scratch.

Using CHTMLListCtrl is very easy just include the required headers and call Create when you want to create it (typically in OnInitdialog).

In the .h file declare a variable:

CHTMLListCtrl m_list;

In the .cpp file:

//Dimentions for the list ctrl
CRect rcList(10,10,400,400);
m_list.Create(this,rcList,123/*Control Id*/); 

//Add imagelist if we want to display images
m_ImageList.Create(16,16,ILC_COLOR24|ILC_MASK,4,4);
m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON_TEST));
m_ImageList.Add(AfxGetApp()->LoadIcon(IDR_MAINFRAME));

m_list.SetImageList(&m_ImageList);

To insert items in the ListCtrl, use the InsertItem function. It takes a few arguments:

int InsertItem(CString sText,UINT uiImage,
                int nStyle=HTML_TEXT,int nHeight=AUTO);
  • sText: The item text (it can be a simple text or a text with HTML tags depending on the nStyle parameter).
  • uiImage: The image number (if an ImageList has been attached, otherwise 0).
  • nStyle: You can specify HTML_TEXT, NORMAL_TEXT and SINGLE_LINE_TEXT (SINGLE_LINE_TEXT will end in ellipses if the text too long).
  • nHeight: You can specify the height of this row or CHTMLListCtrl will calculate it for you.

An example of InsertItem:

CString sText = 
   "<font color=#ff0000><b>Red Bold Font are scary</b></font>";
m_list.InsertItem(sText,0,HTML_TEXT);

To further customize the control's behaviour, you can use the SetExtendedStyle function:

m_list.SetExtendedStyle(HTMLLIST_STYLE_GRIDLINES|
         HTMLLIST_STYLE_CHECKBOX|HTMLLIST_STYLE_IMAGES);
  • HTMLLIST_STYLE_GRIDLINES: Shows/hides gray lines between the items.
  • HTMLLIST_STYLE_CHECKBOX: Adds checkboxes to the items.
  • HTMLLIST_STYLE_IMAGES: Adds images to the items (you have to set an ImageList through the SetImageList function for this to work).

To receive events, you need to handle the WM_NOTIFY Windows message. CHTMLListCtrl supports the following events:

  • HTMLLIST_SELECTIONCHANGED: Fired when list selection changes.
  • HTMLLIST_LBUTTONDOWN: Fired when the left mouse button is down.
  • HTMLLIST_RBUTTONDOWN: Fired when the right mouse button is down.
  • HTMLLIST_LBUTTONDBLCLICK: Fired when the control is double clicked.
  • HTMLLIST_ITEMCHECKED: Fired when the check box state changes.

You will not be able to use the class wizard to handle these events, you will have to manually add the entry in the message map.

In the message map write the following:

BEGIN_MESSAGE_MAP(CMyDlg, CDialog)
   //{{AFX_MSG_MAP(CMyDlg)
   .
   .
   ON_NOTIFY(HTMLLIST_SELECTIONCHANGED,
         123/*list id*/,OnHTMLList_SelChanged)
END_MESSAGE_MAP()

Now add the function:

void CMyDlg::OnHTMLList_SelectionChanged(NMHDR* pNMHDR, 
                                               LRESULT*)
{
    NM_HTMLLISTCTRL *pListNMHDr = 
                  (NM_HTMLLISTCTRL*) pNMHDR;
    if(pListNMHDr->nItemNo != NONE_SELECTED)
    { 
       MessageBox(pListNMHDr->sItemText);
    }
}

Extending the control's functionality

The DrawItem function is implemented as a virtual function, so users can derive from CHTMLListCtrl and draw their own items, for example:

class CMyHTMLListCtrl : public CHTMLListCtrl 
{
public:
   void DrawItem(CDC *pDC,CRect rcItem,
          HTMLLIST_ITEM *pItem,BOOL bSelected)
   {
      //Draw individual items yourself
      ......
   }
}

Credits

The HTML rendering code is taken from Ukkie9's excellent article.

The following points are taken from Ukkie9's article:

  • The only supported tags are <p>, <br>, <font>..</font>, <b>..</b>, <i>..</i>, <u>..</u>, <strong>..</strong>, <em>..</em>, <sub>..</sub> and <sup>..</sup>. The tags <strong>..</strong> are equivalent to <b>..</b>, and <em>..</em> map to <i>..</i>.
  • The <font> tag is used only for changing the text color. It is also the only tag that can take a parameter, and this parameter should be "color" with a value in the well known HTML hexadecimal notation. For example, "<font color='#ffff00'>".
  • With the exception of tags that take parameters (currently, only the <font> tag), there can be no spaces in the tags; <p> is okay, but <p align='right'> will be considered as two words "<p" and "align='right'>". That's right: when DrawHTML() considers that something is not a valid HTML tag, it prints it as a word.
  • Special characters like < and à are not supported, you must type in the correct characters. That is, you can just use the characters "à" and "&" in the text, and "<" too.

CHTMLListCtrl also uses the CMemDC written by Keith Rules, which can be downloaded from here (it is also included in the zip files above).

History

  • 26th April, 2006
    • CalculateItemHeight bug fixed.
    • WTL version added (thanks to Ernest Laurentin).
    • SetCursor bug fixed.
    • Resizing bug fixed.
  • 23rd March, 2006
    • CFont handle released in OnDestroy.
    • Invalidate(FALSE); added in OnSize.
    • GetItemCount function added (DUH).
  • 17th March, 2006
    • Initial release.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Monty2
Web Developer
India India
Programming Since the the Dreaded 286 Assembly Days
 
currently MFC and ATL NUT
 

Don't take life seriously because you can't come out of it alive.
-Warren Miller

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Questiondinamic update items in HtmlListCtrl.display items one by one must show in controlmembersunil.m12324-Nov-11 1:38 
dinamic update items in HtmlListCtrl.display items one by one must show in control
QuestionHICON memory leakmembersunil.m12316-Sep-11 20:56 
when displaying more icons.Refresh Button functionality ,after some clicks application is crashing,plz can u suggest me any way to solve this bug.
QuestionClistctrl relatedmemberdecoder_8523-Nov-10 0:43 
Hi, I saw this project and its really good. I am developing a custom list control in report view and i need to color the substring of one of the column text based on some condition. e.g. row 2 and column 3 has text written " Hello World" and i have to color just "world" to some color. How would i be able to do that. Please suggest any method in report view as i am using dialog to display the list control. I couldnt figure out from your source code.
GeneralSome code update (small bug found) [modified]memberVaKa3-Dec-09 10:10 
in CHTMLListCtrl::CalculateItemHeight(...) we dont take into account presence of vertical scroll bar...
so when it shown, real list item width is smaller then width of control window.
 
to correct this, we can use, for example, next code update:
 
int CHTMLListCtrl::CalculateItemHeight(CString sText, int nStyle)
{
// Vertica Scroll Bar presence correction
int nScrlWidth=0;
int nWndWidth = m_nWndWidth;
SCROLLBARINFO scrlinfo;
ZeroMemory(&scrlinfo,sizeof(SCROLLBARINFO));
 
scrlinfo.cbSize = sizeof(SCROLLBARINFO);
if(GetScrollBarInfo(m_hWnd,OBJID_VSCROLL,&scrlinfo))
{
if(!(scrlinfo.rgstate[0] & STATE_SYSTEM_INVISIBLE)){
CRect rc(scrlinfo.rcScrollBar);
nScrlWidth = max(0,rc.Width());
nWndWidth -= nScrlWidth; // small corrections of width
}
}
// Vertica Scroll Bar presence correction
// in following code m_nWndWidth replaced by nWndWidth
if(nStyle == NORMAL_TEXT)
{
CDC *pDC = GetDC();

CFont *pOldFont = pDC->SelectObject(&m_font);
 
CRect rc;
rc.SetRectEmpty();
 
rc.left = 0;
 
if(m_dwExtendedStyles & HTMLLIST_STYLE_CHECKBOX)
{
rc.right = nWndWidth - ITEM_CHECKBOX_WIDTH - ITEM_PADDING_LEFT;
}
else
{
rc.right = nWndWidth - ITEM_PADDING_LEFT;
}

pDC->DrawText(sText,&rc,DT_WORDBREAK|DT_CALCRECT|DT_EXTERNALLEADING );
 
pDC->SelectObject(pOldFont);
ReleaseDC(pDC);
return rc.Height() + ITEM_PADDING_BOTTOM + ITEM_PADDING_TOP;
}
else if(nStyle == HTML_TEXT)
{
CDC *pDC = GetDC();

CDC memDC;
memDC.CreateCompatibleDC(pDC);
 
CFont *pOldFont = memDC.SelectObject(&m_font);
 
int nWidth = 0;
 
CRect rc2;
 
GetClientRect(rc2);
 
if(m_dwExtendedStyles & HTMLLIST_STYLE_CHECKBOX)
{
nWidth = nWndWidth - ITEM_CHECKBOX_WIDTH - ITEM_PADDING_LEFT;
}
else
{
nWidth = nWndWidth - ITEM_PADDING_LEFT ;
}
 
CRect rc(0,0,nWidth,m_nWndHeight);
 
int nHeight = DrawHTML(memDC.GetSafeHdc(),
sText,
sText.GetLength(),
&rc,
DT_LEFT|DT_CALCRECT|DT_WORDBREAK|DT_EXTERNALLEADING);
 
memDC.SelectObject(pOldFont);
ReleaseDC(pDC);
return rc.Height() + ITEM_PADDING_BOTTOM + ITEM_PADDING_TOP;
}
else if(nStyle == SINGLE_LINE_TEXT)
{
CDC *pDC = GetDC();

CFont *pOldFont = pDC->SelectObject(&m_font);
 
CRect rc;
rc.SetRectEmpty();
 
rc.left = 0;
 
if(m_dwExtendedStyles & HTMLLIST_STYLE_CHECKBOX)
{
rc.right = nWndWidth - ITEM_CHECKBOX_WIDTH - ITEM_PADDING_LEFT;
}
else
{
rc.right = nWndWidth - ITEM_PADDING_LEFT;
}
 
pDC->DrawText(sText,&rc,DT_VCENTER|DT_CALCRECT|DT_SINGLELINE);
 
pDC->SelectObject(pOldFont);
ReleaseDC(pDC);
return rc.Height() + ITEM_PADDING_BOTTOM + ITEM_PADDING_TOP;
}
return 0;
}
 
modified on Thursday, December 3, 2009 4:26 PM

Questionhow to multi select items use ctrl and left mouse buttonmemberbunpkin6-Sep-09 4:09 
it's nice code,thank for share
AnswerRe: how to multi select items use ctrl and left mouse buttonmemberbunpkin6-Sep-09 7:12 
I try to do this ,any better way?
 
void XXX::OnLButtonDown(UINT nFlags, CPoint point)
{
....
if (nFlags == MK_CONTROL + 1)
{
m_selectedItem->checked = !m_selectedItem->checked;
if (m_selectedItem->checked )
m_selectedItem->Status = BTN_STATUS_PRESSED;
else
m_selectedItem->Status = BTN_STATUS_NORMAL;
}
else
{
clearSelection();
m_selectedItem->Status = BTN_STATUS_PRESSED;
}
....
}
Generalicon and picturemembersapna_ds16-Jun-09 0:41 
hi,
is there any way that i can display an icon like you do with the mainframe one and an additional picture? i need the icon for a list control in an IM to show the status and the picture for the contact picture. is this possible?
 
Thanks,
sapna
GeneralClear selection when clicking on a whitespacmemberMichael A. Rusakov23-Apr-09 2:08 
Hi, first of all I would like to say thank you for such pretty-looking list control. I'm just trying to use it, but I'm impressed!
 
One suggestion: if you click on an item, it will be selected (right behaviour). If you click on a whitespace, the selected item will remain visually selected (however inside list control the selection variable is cleared). I'm compilling under VS 2008.
 
So, I have added Invalidate(TRUE) into OnLButtonDown() function:

if(!bItemSelected)
{
//.....
delete pNMHDR;
 
Invalidate(TRUE); // <-- Here
}

 
Thanks again for the control... Thumbs Up | :thumbsup:
 
Sincerely,
Michael Rusakov.
http://www.wincatalog.com

GeneralGreat work! Plus mods.memberJustinDOliver22-Sep-08 10:23 
Hi, I just wanted to thank you for your great work on this. I also wanted to let you know that I made a few minor mods to this control so it can run in Windows CE/Mobile. If you are interested in the mods, let me know and I can mail them to you.
 
Justin

GeneralRe: Great work! Plus mods.memberMonty222-Sep-08 15:55 
Thank you for your kind words and yes i am interested in the mods Smile | :)
 

C++ where friends have access to your private members !

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130617.1 | Last Updated 2 May 2006
Article Copyright 2006 by Monty2
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid