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

A Simple HTML drawing class

By , 5 Aug 2003
 
Sample Image - HTMLDrawer.gif

Introduction

For one of my projects, I needed to display some rich text in a Windows environment and in a browser and wanted them to appear roughly the same. I did not need to embed images or hyper-links, only some simple text formatting like the colour, the font name and the bold/italic/underline attributes. I also wanted to be able to control the background appearance. Using a HTML or a Rich Text control was therefore not an obvious option.

My intent was not to re-invent the wheel and provide a real HTML parser, simply a reduced HTML viewer that I could use almost anywhere. Feel free to improve the code and add support to other HTML tags (or your own if needed). Keep me posted of any improvements you make so I can upgrade the source (oh and my project).

I was then informed that Hans Dietrich had done a very similar development http://www.codeproject.com/staticctrl/XHTMLStatic.asp. Looking at his control and inspired by a few of the comments posted there, I decided to create another control CHTMLStatic that would support hyperlinks and the <p> tag.

Background

Now comes the condescending section! Anyway, here is the list of tags supported by the Drawer:

  • <B> and </B> or <STRONG> and </STRONG> : sets the text between the tags in bold
  • <I> and </I> or <EM> and </EM>: sets the text in italic
  • <U> and </U>: underlines the text
  • <FONT> and </FONT>: sets the font name, size and colour (The attributes supported are FACE, COLOR and SIZE). You can specify a colour by its rgb values or by its name (entering the list was rather painful)
  • <BR>: adds a line break.
  • <P>: Defines a paragraph. The only supported attribute is ALIGN (values can be left, center or right).
  • <CENTER>: Defines a centered paragraph.
  • <A HREF=url>: Defines an hyperlink.

Two main points are not in compliance with HTML:

  1. When 2 spaces are encountered, HTML assumes there is only one. I don't
  2. The new line character is interpreted as a space in HTML, not here

These would be easy to implement if you need them.

Using the code

You can either use the code with CHTMLDrawer and its static function DrawText. This would only render the HTML and not allow you to use the hyperlinks.

/////////////////////////////////////////////////////////////
// DrawText
/////////////////////////////////////////////////////////////
// Parameters:
// pDC : Device context
// strText: Text to be drawn
// fntDefault : Default font to be used
// rctPosition : Rectangle in which the text is to be drawn
// nAlignment: 0 (left) or 1 (centered) or 2 (right)
/////////////////////////////////////////////////////////////
void CHTMLDrawer::DrawText(CDC * pDC, const CString & strText,
            const CHTMLFont & fntDefault,CRect & rctPosition,short nAlignment)

Alternatively, you could use the control CHTMLStatic. You can define its background colour, the default font used, the color of a highlighted hyperlink and if it is underlined when highlighted.

CHTMLFont encapsulates the definition of a font (name, attributes, size and colour). You will need it to define the default font used. CHTMLAtom is used as a temporary storage class and you will probably not need to refer to it in your code.

How it is done:

  1. Try to break the text into smaller parts that would have the same font settings. This is what I call an atom. This is done in ParseHTMLText()
  2. Then whenever an atom overruns the right side of the rectangle, it is broken into smaller atoms (trying to break it where there are spaces). This function also computes the positions of atoms for their display. Check BreakIntoLines() for details.
    We also keep track of the atoms linked to a URL.
  3. Finally, we find the position of the lowest atom to centre the text vertically and apply the alignments in ApplyAlignments
  4. The actual drawing is done in DrawAtoms

Remarks

The whole thing is not too complicated, although I am pretty sure there are still a few bugs left and much room for optimization. Feel free to use it as much as you want as long you do not make me responsible for undesirable side effects!

Portions of the code were inspired (or copied) from Hans Dietrich who himself borrowed from Chris Maunder who himself is an avid reader of Paul DiLascia's MSJ column.

History

  • 23/3/2003: v1.0
  • 11/4/2003: v1.1
    Added the control CHTMLStatic which supports hyperlinks (and the text stays nicely in the boundaries - thanks Doc McClenny).
    Added support of the following tags: <P>, <CENTER>, <A HREF=url> and <EM>.
    Text of different font sizes is correctly aligned and removed the 7 upperboud for a font size (thanks to Chopper for his comment).
    And finally thanks to Hockey for showing me Hans Dietrich's article that I have shamelessly looted...
  • 4/8/2003: v1.2
    I have a corrected a few bugs on CHTMLStatic, the control encapsulating the drawer - resize problems and flickering of the cursor (thanks to Pranavamhari's remark)
    I have also added a new sample encapsulating the drawer into a view which allows a vertical scroll bar (this was Koh Zi Chun's idea... thanks for the positive feedback!)

License

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

About the Author

BadJerry
Web Developer
United Kingdom United Kingdom
Member
Known as "The Wandering Geek", I have had to often change identities and countries due to the low quality level of the numerous software I have left behind.
Never wrote a software that did more than sorting 3 numbers which actually worked.
Hey but feel free to download my stuff!
 

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   
Generalnicemembernyeboy8 Apr '11 - 4:50 
It's a useful something. I download that, and then thank you.
studing is processing in this life.

Generalthat thing doesn't work on Windows Mobilememberglook11 Sep '08 - 1:34 
I mean CHTMLDrawerView...
first of all, there is no WM_INITIALUPDATE on Windows Mobile.
so I made OnInitialUpdate public to call it directly.
but when I draw the control, it looks good as far as I don't try to scroll...
scrollbar moves corrdctly, but the text is corrupted badly..
 
please, tell me, what's wrong?
 
PS: sorry for my bad English... Wink | ;)
GeneralRe: that thing doesn't work on Windows MobilememberBadJerry11 Sep '08 - 5:14 
Don't you worry about the bad English - it's a pretty common thing...
I have not tried the view on mobile - the rest works pretty well. I suspect all it needs is a refresh on the WM_VSCROLL event. Feel free to send me a small sample so I can have a look at it...
jerome at askia dot com
AnswerRe: that thing doesn't work on Windows Mobilememberglook11 Sep '08 - 6:27 
first of all, I've commented Dump, SetDefaultCursor, GotoURL, GetRegKey and OnLButtonDown, because I don't need hyperlinks and cursors (Windows Mobile don't have a cursor =) )
 
then, in OnInitDialog of my dialog I do following:
 
	DWORD dwStyle = AFX_WS_DEFAULT_VIEW;
	pView = (CHTMLDrawerView*) RUNTIME_CLASS(CHTMLDrawerView)->CreateObject();
	if (pView->Create(NULL, NULL, dwStyle, rctPosition, this, 100, NULL))
	{
		pView->SetParent(this);
		pView->SetScript( _ long HTML here... _ );
		pView->UpdateWindow(); // or without it - it doesn't matter
	}
 
and I've added
 
void CHTMLDrawerView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
	UpdateWindow();
	// TODO: Add your message handler code here and/or call default
	CScrollView::OnVScroll(nSBCode, nPos, pScrollBar);
}
 
but no effect... still missing text after scroll.
 
and CHTMLDrawerView::OnInitialUpdate is never called.
 
I sent you a sample MFC project (MSVS2008) with modifyed files
 
=)
GeneralRe: that thing doesn't work on Windows MobilememberBadJerry11 Sep '08 - 23:26 
The problem comes from the fact that SetViewportOrg does work in windows mobile (why?)
This means you need to implement it by hand.
I'll send you the updated files now
Anyone who want the files, drop me an e-mail - I might even update the files here one day if there is overwhelming demand fir it(ha!)
 
Jerome
GeneralRe: that thing doesn't work on Windows Mobilememberglook15 Sep '08 - 2:39 
thanx a lot! =) this works, but I didn't get where did you implement SetViewportOrg? search didn't give an answer...
QuestionHow do I get the source code of html?membershertay6 Feb '06 - 16:36 
Instead of inputting the source code, I would like to get the source code from the html but I do not know how to get it. Any idea?
AnswerRe: How do I get the source code of html?memberBadJerry7 Feb '06 - 22:38 
I am pretty sure this control will not be of any help... but you should try to use a CHtmlView and work from there!
I am afraid I am not going to be of more help but do ask on the C++ forum[^]
Good luck!
GeneralNice Work + A Bug + EnhancementmemberAamir Butt6 Oct '04 - 23:29 
Very nice work mate. You get my 5.
 
Well, I think I have found a bug in it as well. I was trying to use this code with CMetaFileDC and I got an Assert followed by a crash at GetTextExtent & GetTextMetrics calls. I have simply replaced these two by GetOutputTextExtent & GetOutputTextMetrics and now its working fine.
 
I am set to enhance it to include some more tags which include <INPUT>, <TEXTAREA>, <SELECT> and <IMG>. I hope to get these done early and will surely post a message here when I am done.
 
Regards,
 

Imagine that you are creating a fabric of human destiny with the object of making men happy in the end, giving them peace and rest at last, but that it was essential and inevitable to torture to death only one tiny creature..and to found that edifice on its unavenged tears, would you consent to be the architect on those conditions? Tell me, and tell me the truth!
 
-Fyodor Dostoevsky, The Brothers Karamazov

GeneralRe: Nice Work + A Bug + EnhancementmemberBadJerry7 Oct '04 - 3:31 
Thanks for this! Especially as there are quite a few of these classes around on CodeProject!
 
You will see that <img> is a killer as you need to wrap the text around the image...
The one thing that keeps being asked is support for and
...
Keep me posted on your progress!
 
Best of luck!
Generalmeasure end atom of 1 page..sussLee C.H.12 Aug '03 - 17:50 
Wink | ;) Hi BadJerry,
I has load html file to your control but, html file string has so long document that can't contain your control.
So, I wanna divide html file string for fit your control.
I wanna measure end atom of 1's page.
How do I?..
 
thanks, BadJerry..

GeneralRe: measure end atom of 1 page..memberBadJerry12 Aug '03 - 23:46 
Hi Lee,
 
not completely sure I understand your question but
a) You can use the new project I have added (project2) which is an implementation of the drawer in a scroll view
b) A bit of work:
1) You could update the whole class so you would keep in the atoms the position in the orginal HTML code
2) parse your HTML file to get the list of atoms calling CHTMLDrawer::PrepareDraw
3)
then you could go through the array m_arrDisplayAtoms with somethig like this

for ( int nAtom = 0; nAtom < m_arrDisplayAtoms.GetSize(); nAtom++)
{
   CHTMLAtom * pAtom = (CHTMLAtom *) m_arrDisplayAtoms.GetAt(nAtom);
    if ( pAtom->GetPosition().bottom > nMaxHeight )
    {
      // TO DO : Break the HTML script here
    }
}

Does that make sense? Let me know how you are doing!
Good luck!

GeneralThanks! Thanks! Thanks!sussLee C.H.16 Aug '03 - 23:03 
I am developing E-Book software for PPC with your control modified.
Thanks, BadJerry.

GeneralRe: Thanks! Thanks! Thanks!memberpranavamhari17 Aug '03 - 20:33 
If you are using a modified code, could you please post here the tweaks you made ? perhaps that would be of use to us.

 
Hari Krishnan
QuestionHow to reduce sentence's gap?memberLee C.H.6 Aug '03 - 22:00 

I tried to reduce sentence's gap..but I cant..
Cry | :((
How do I work?
AnswerRe: How to reduce sentence's gap?memberBadJerry6 Aug '03 - 23:55 
Hi Lee,
 
If you want to reduce the gap between lines (I hope I got your question right), modify in CHTMLDrawer::CreateNewLine:

nY=rctTextPosition.bottom+1;

by

nY=rctTextPosition.bottom-3;

 
and further down in the same function

nY=nMaxBottom+1;

by

nY=nMaxBottom-3;

 
You can tweak with the parameter (3 above) so you get your line spacing right!
 
I hope this helps!
 


GeneralGood .......but how about tablemember_skidrow_vn_6 Aug '03 - 21:05 
I want to create table in HTML form ????Confused | :confused:
GeneralRe: Good .......but how about tablememberI'm a code monkey6 Aug '03 - 21:33 
try: http://www.gipsysoft.com/qhtm/
GeneralRe: Good .......but how about tablememberBadJerry7 Aug '03 - 0:17 
Sorry no plan to integrate tables or images (no plan for a javascript compiler either Smile | :) ). Well tables maybe one day...
 
But if you do it in the meantime, keep us informed!
GeneralRe: Good .......but how about tablemember_skidrow_vn_7 Aug '03 - 13:35 
Yeah............... I really want to write a HTML file
More detail:
I have a "Product" table in database then ........ I want to use HTML form to display this table then print it.... a easiest way to print out a report (rely HTML form
....)
But I have problem when write table to file
because column number and row number is variable, string len of each cell in table is variable, too
Dead | X|
GeneralBugmemberpranavamhari1 Aug '03 - 21:41 
HI,
I think i've found two bugs.
 
The first and most serious one
After the cursor chnages to 'hand' on moving over a link, when we try to resize the dialog, the diaonal resize cursors flicker. This is due to the 'CHtmlStatis::Ontimer' func.
 
The second one.
The underlining of link does not happen after the first time.
 
may be both are related.
 


 
Hari Krishnan
GeneralRe: BugmemberBadJerry3 Aug '03 - 23:46 
Hi!
 
Thanks for your comments... the two bugs are not related but nevertheless corrected...
The first one was due to the fact that I was reaffecting the cursor all the time to the first observed cursor which was annoying if the cursor did change (as in the case of a resize). It is now solved! Check OnSetCursor and OnTimer!

The second one was due to the fact that the HTML atoms' positions had to be recalculated after a resize of the control. Adding a handler on WM_SIZE with the following code did the trick:

void CHTMLStatic::OnSize(UINT nType, int cx, int cy)
{
   CStatic::OnSize(nType, cx, cy);

   // Recalculate the positions of controls
   m_isTextPrepared = false;
   Invalidate(true);
}

 
Send me an e-mail if you want the code changes now. I will post them anyway onto codeproject!
 


GeneralOne suggestionmemberAmit Dey27 Apr '03 - 3:31 
would be to change the title HTML 'Drawer' to HTML 'Renderer'. Render would be more appropriate because drawer, also means underwear. Smile | :)
 
But a nice article.
 


Hush,hush...
thought I heard you call my name now.

Kula Shaker.

Amit Dey

Latest articles at CP -
PocketPC New menu
Office addin

GeneralAll fetichists welcomememberBadJerry1 May '03 - 0:06 
ah... however long you have been speaking English, you are still cruelly reminded that there is still a long way before you can grasp all of its peculiarities.
Well if it can improve the rating of the site - surely "drawers" and "fetichists" on the same page should bring a few hits!
 
Bad Jerry
GeneralRe: All fetichists welcomesussAnonymous1 May '03 - 12:16 
Take nothing to heart. Rose | [Rose]
 
How long have you been speaking English and [if not English] what do you normally speak?Smile | :)

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.130516.1 | Last Updated 6 Aug 2003
Article Copyright 2003 by BadJerry
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid