Click here to Skip to main content
15,867,686 members
Articles / Desktop Programming / MFC
Article

Controls-in-controls: A line-numbering edit box

Rate me:
Please Sign up or sign in to vote.
4.91/5 (24 votes)
11 May 2004Public Domain5 min read 138.2K   6.3K   63   27
A line-numbering edit control

Sample Image - linenumberedit.gif

Introduction

CLineNumberEdit is a CEdit-derived class with automatic line-numbering along the left margin. Colors for the sidebar are editable, so is the format of the line numbers. The subclassing is an experiment in containing controls inside an edit box, and even if I have added enough functionality to make the class mildly useful, the primary goal is to investigate this containment (see also www.codeproject.com/editctrl/editwithicon.asp).

Using the code

Include the cpp- and h-file to the project. CLineNumberEdit can be instantiated either dynamically, by a call to Create, or from a dialog template. In the latter case, a control variable can be created and bound to the control with the class wizard, or SubclassDlgItem can be used.

Public members of this class:

To set the background color of the line number field, call SetMarginBackgroundColor. The default is RGB( 255, 255, 248 ) (see the picture)

SetMarginForegroundColor will set the text color. The default is black.

SetLineNumberFormat sets a formatting string, later used with CString::Format, so it follows the rules for this call. The format string must contain one (and only one) numerical type, of course. The default is "%05i", yielding a right aligned, zero-padded 5 character string.

In PreSubclassWindow, the edit box style is checked. If it doesn't contain ES_MULTILINE, the class ASSERTs. Apart from being slightly irrelevant for non-multi line edits, to say the least, the SetRect call used to make place for the line numbers will not work for single-line edits.

The margin is set up in Prepare. Here, the necessary width of the line-number field is calculated. This is accomplished by creating a string, using the control format string, formatting it with the max number of characters for the control (calling CEdit::GetLimitText). This assumes that each line will only be one character long, so we know that this will be our maximum number of lines. The string is measured, and a small margin is added.

Finally, a CLineNumberStatic - a CStatic-derived control - is created with the desired size. The top- and bottom line of the edit box is sent to this control. The top margin is also set.

CLineNumberStatic is a simple CStatic-derived class, managing the painting of the line-numbers through OnPaint. The drawing is made to a memory CDC and blitted to the screen, and WM_ERASEBKGND is handled to avoid flicker.

The CLineNumberStatic is synchronized to the CLineNumberEdit by setting new top- and bottom-line values. This has to be done as soon as the control is scrolled, and/or when the contents are changed. Fortunately, this is simple - by handling the EN_CHANGE and WM_SETTEXT messages for modifications, and EN_VSCROLL plus WM_VSCROLL for scrolling. EN_VSCROLL takes car of scrolling "inside" the edit (such as moving with the arrow keys), WM_VSCROLL updates the line-numbers while the thumb-track is moved.

WM_SIZE is handled, both to reestablish the line-number field size and the edit rectangle. Finally, WM_SETFONT is also handled to reestablish the edit rectangle - as it is reset when the control receives this message. WM_SETFONT will also make it necessary to redraw the line-number control.

Points of Interest

This control presented a few problems. The edit control and the line number static must be synchronized. The edit rectangle must be re-established as soon as it is destroyed. Primarily, the problem is to find the messages sent to the control where those two tasks must be accomplished. A murky area is when the edit rectangle gets destroyed, I've later found that SetWindowPlacement also does this - with no solution other than "use MoveWindow instead".

Getting the first visible line is simple - it's just to call GetFirstVisibleLine. The bottom one is trickier, however. I first tried this using the really devious method of getting the difference between two lines, using a blend of calls to GetLine and GetPosFromChar, but the contents of the control was not reformatted in a way to make this reliably possible. Now, I simply use the height of a line in the font of the control, and the top margin from GetRect of the parent.

History

Dawn of time

First version

14/4 2004

Some really nice additions from Keith Bowes; the possibility to use system colors for the line-number part, and handling of start- and max values.

UseSystemColours( BOOL bUseEnabled = TRUE, BOOL bUseDisabled = TRUE ); can be called to use the current system colors for the enabled and disabled state respectively.

SetLineNumberRange( UINT nMin, UINT nMax = 0 ); can be used to set the starting line number and the max number of lines to be numbered. Note that this is not a min-max range, a minimum value of 100 and a max of 10 will number the lines from 100, 101, 102 etc. up to 109.

Setting nMax to zero means no upper limit. Lines above the max-value will not be numbered, although they will of course still be displayed.

22/4 2004

A new addition from Keith Bowes - handling of the WM_LINESCROLL message. This is community spirit!

Not to be outdone, I've added code for selecting a complete line by clicking on the line number. Accomplished by a registered message, and click-handling on the line-number control.

Added a small demo-program. I realize that some people might just want to take a look - creating a project just for this reason is perhaps a bit much :-)

License

This article, along with any associated source code and files, is licensed under A Public Domain dedication


Written By
Software Developer (Senior) Abstrakt Mekanik AB
Sweden Sweden
45 years old, married, three kids.

Started with computers more than 20 years ago on a CBM-64.

Read Theoretical Philosophy at the University of Lund.

Working as a C++ consultant developer.

Science-fiction freak. Enjoy vintage punkrock.

Comments and Discussions

 
GeneralMy vote of 5 Pin
Member 1242464210-May-16 16:21
Member 1242464210-May-16 16:21 
QuestionDynamic creation of line-number edit box ERROR Pin
sunfei28-Feb-13 20:03
sunfei28-Feb-13 20:03 
QuestionHow could I Create CLineNumberEdit dynamically ? Pin
anceswu21-Dec-11 19:41
anceswu21-Dec-11 19:41 
GeneralAdaptation to Rich Text Pin
flyontheweb14-Oct-10 5:59
flyontheweb14-Oct-10 5:59 
GeneralThanks for the code! Pin
David Howe21-May-07 15:47
David Howe21-May-07 15:47 
GeneralRe: Thanks for the code! Pin
Johan Rosengren22-May-07 6:26
Johan Rosengren22-May-07 6:26 
Questionin Visual Basic .NET?? Pin
uniquekaiser12-Feb-07 19:12
uniquekaiser12-Feb-07 19:12 
AnswerRe: in Visual Basic .NET?? Pin
Johan Rosengren13-Feb-07 6:27
Johan Rosengren13-Feb-07 6:27 
GeneralFlickering Pin
nightrider1327-Dec-06 8:59
nightrider1327-Dec-06 8:59 
GeneralRe: Flickering Pin
Johan Rosengren27-Dec-06 19:50
Johan Rosengren27-Dec-06 19:50 
GeneralRe: Flickering Pin
nightrider1328-Dec-06 2:21
nightrider1328-Dec-06 2:21 
GeneralRe: Flickering Pin
Johan Rosengren28-Dec-06 4:23
Johan Rosengren28-Dec-06 4:23 
GeneralRe: Flickering Pin
nightrider1328-Dec-06 14:41
nightrider1328-Dec-06 14:41 
GeneralRe: Flickering Pin
Johan Rosengren28-Dec-06 21:24
Johan Rosengren28-Dec-06 21:24 
GeneralRe: Flickering Pin
nightrider1331-Dec-06 17:07
nightrider1331-Dec-06 17:07 
Okay, I have solved the problem.
Thank you very much and i wish you a good new year.
GeneralGood Job Pin
CourageousSam11-Dec-06 8:04
CourageousSam11-Dec-06 8:04 
GeneralRe: Good Job Pin
Johan Rosengren13-Dec-06 6:44
Johan Rosengren13-Dec-06 6:44 
GeneralNice Pin
Bassam Abdul-Baki6-Apr-06 5:09
professionalBassam Abdul-Baki6-Apr-06 5:09 
GeneralRe: Nice Pin
Johan Rosengren8-Apr-06 23:03
Johan Rosengren8-Apr-06 23:03 
GeneralBug Pin
Johann Gerell13-May-04 22:13
Johann Gerell13-May-04 22:13 
GeneralRe: Bug Pin
Johan Rosengren13-May-04 22:59
Johan Rosengren13-May-04 22:59 
QuestionHow to change it to CEditView? Pin
transoft12-May-04 6:19
transoft12-May-04 6:19 
AnswerRe: How to change it to CEditView? Pin
Johan Rosengren12-May-04 8:01
Johan Rosengren12-May-04 8:01 
GeneralPlug & play missing! Pin
andyj11510-Mar-04 6:54
andyj11510-Mar-04 6:54 
GeneralRe: Plug & play missing! Pin
Johan Rosengren10-Mar-04 8:19
Johan Rosengren10-Mar-04 8:19 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.