Line Numbering a RichTextBox

rowanjl

Newcomer
Joined
Sep 21, 2005
Messages
7
I'm currently working on a control extended from the RichTextBox control, it supports brace completion, quotation completion, HTML element completion and smart indentation.

I want to add line numbers like most common editors, can anyone point me in the right direction? Thanks!
 
the PARAFORMAT2 Structure is what you want to be searching for.
the specific area being ...
wNumbering Options used for bulleted or numbered paragraphs. To use this member, set the PFM_NUMBERING flag in the dwMask member. This member can be one of the following values.

zero No paragraph numbering or bullets. PFN_BULLET Insert a bullet at the beginning of each selected paragraph.Rich Edit versions earlier than version 3.0 do not display paragraph numbers. However, for compatibility with Microsoft Text Object Model (TOM) interfaces, wNumbering can specify one of the following values. (The rich edit control stores the value but does not use it to display the text.)

2 Uses Arabic numbers (1, 2, 3, ...). 3 Uses lowercase letters (a, b, c, ...). 4 Uses uppercase letters (A, B, C, ...). 5 Uses lowercase Roman numerals (i, ii, iii, ...). 6 Uses uppercase Roman numerals (I, II, III, ...). 7 Uses a sequence of characters beginning with the Unicode character specified by the wNumberingStart member. to get the current paraformat you need to call EM_GETPARAFORMAT Message
to set the paramformat ( with any changes you have added ) EM_SETPARAFORMAT Message
 
i decided to knock an example together for you, i already have an indepth C# richtext api, so i've quite literally translated the PARAFORMAT2 structure over.
Visual Basic:
[size=2]
<StructLayout(LayoutKind.Sequential)> _
[size=2][color=#0000ff]Public [/color][/size][size=2][color=#0000ff]Structure[/color][/size][size=2] PARAFORMAT2
[/size][size=2][color=#0000ff]    Public[/color][/size][size=2] cbSize [/size][size=2][color=#0000ff]As[/color][/size][size=2] Int32
[/size][size=2][color=#0000ff]    Public[/color][/size][size=2] dwMask [/size][size=2][color=#0000ff]As[/color][/size][size=2] Int32[/size]
[size=2][color=#0000ff]    Public[/color][/size][size=2] wNumbering [/size][size=2][color=#0000ff]As[/color][/size][size=2] Int16
[/size][size=2][color=#0000ff]    Public[/color][/size][size=2] wReserved [/size][size=2][color=#0000ff]As[/color][/size][size=2] Int16
[/size][size=2][color=#0000ff]    Public[/color][/size][size=2] dxStartIndent [/size][size=2][color=#0000ff]As[/color][/size][size=2] IntPtr
[/size][size=2][color=#0000ff]    Public[/color][/size][size=2] dxRightIndent [/size][size=2][color=#0000ff]As[/color][/size][size=2] IntPtr
[/size][size=2][color=#0000ff]    Public[/color][/size][size=2] dxOffset [/size][size=2][color=#0000ff]As[/color][/size][size=2] IntPtr
[/size][size=2][color=#0000ff]    Public[/color][/size][size=2] wAlignment [/size][size=2][color=#0000ff]As[/color][/size][size=2] Int16
[/size][size=2][color=#0000ff]    Public[/color][/size][size=2] cTabCount [/size][size=2][color=#0000ff]As[/color][/size][size=2][color=#0000ff]Short
[/color][/size][size=2]    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=32)> _
[/size][size=2][color=#0000ff]    Public[/color][/size][size=2] rgxTabs() [/size][size=2][color=#0000ff]As[/color][/size][size=2] IntPtr
[/size][size=2][color=#0000ff]    Public[/color][/size][size=2] dySpaceBefore [/size][size=2][color=#0000ff]As[/color][/size][size=2] IntPtr
[/size][size=2][color=#0000ff]    Public[/color][/size][size=2] dySpaceAfter [/size][size=2][color=#0000ff]As[/color][/size][size=2] IntPtr
[/size][size=2][color=#0000ff]    Public[/color][/size][size=2] dyLineSpacing [/size][size=2][color=#0000ff]As[/color][/size][size=2] IntPtr
[/size][size=2][color=#0000ff]    Public[/color][/size][size=2] sStyle [/size][size=2][color=#0000ff]As[/color][/size][size=2][color=#0000ff]Short
[/color][/size][size=2][color=#0000ff]    Public[/color][/size][size=2] bLineSpacingRule [/size][size=2][color=#0000ff]As[/color][/size][size=2][color=#0000ff]Byte
[/color][/size][size=2][color=#0000ff]    Public[/color][/size][size=2] bOutlineLevel [/size][size=2][color=#0000ff]As[/color][/size][size=2][color=#0000ff]Byte
[/color][/size][size=2][color=#0000ff]    Public[/color][/size][size=2] wShadingWeight [/size][size=2][color=#0000ff]As[/color][/size][size=2] Int16
[/size][size=2][color=#0000ff]    Public[/color][/size][size=2] wShadingStyle [/size][size=2][color=#0000ff]As[/color][/size][size=2] Int16
[/size][size=2][color=#0000ff]    Public[/color][/size][size=2] wNumberingStart [/size][size=2][color=#0000ff]As[/color][/size][size=2] Int16
[/size][size=2][color=#0000ff]    Public[/color][/size][size=2] wNumberingStyle [/size][size=2][color=#0000ff]As[/color][/size][size=2] Int16
[/size][size=2][color=#0000ff]    Public[/color][/size][size=2] wNumberingTab [/size][size=2][color=#0000ff]As[/color][/size][size=2] Int16
[/size][size=2][color=#0000ff]    Public[/color][/size][size=2] wBorderSpace [/size][size=2][color=#0000ff]As[/color][/size][size=2] Int16
[/size][size=2][color=#0000ff]    Public[/color][/size][size=2] wBorderWidth [/size][size=2][color=#0000ff]As[/color][/size][size=2] Int16
[/size][size=2][color=#0000ff]    Public[/color][/size][size=2] wBorders [/size][size=2][color=#0000ff]As[/color][/size][size=2] Int16
[/size][size=2][color=#0000ff]End [/color][/size][size=2][color=#0000ff]Structure[/color][/size]
[size=2][color=#0000ff] 
[/color][/size][size=2]<DllImport("user32", CharSet:=CharSet.Auto)> _ 
[/size][size=2][color=#0000ff]Private [/color][/size][size=2][color=#0000ff]Shared [/color][/size][size=2][color=#0000ff]Function[/color][/size][size=2] SendMessage( _
[/size][size=2][color=#0000ff]    ByVal[/color][/size][size=2] hWnd [/size][size=2][color=#0000ff]As[/color][/size][size=2] HandleRef, _
[/size][size=2][color=#0000ff]    ByVal[/color][/size][size=2] msg [/size][size=2][color=#0000ff]As[/color][/size][size=2] Int32, _
[/size][size=2][color=#0000ff]    ByVal[/color][/size][size=2] wParam [/size][size=2][color=#0000ff]As[/color][/size][size=2] Int32, _
[/size][size=2][color=#0000ff]    ByVal[/color][/size][size=2] lParam [/size][size=2][color=#0000ff]As[/color][/size][size=2] Int32) [/size][size=2][color=#0000ff]As[/color][/size][size=2] Int32
[/size][size=2][color=#0000ff]End [/color][/size][size=2][color=#0000ff]Function
 
[/color][/size][size=2]<DllImport("user32", CharSet:=CharSet.Auto)> _
[/size][size=2][color=#0000ff]Private [/color][/size][size=2][color=#0000ff]Shared [/color][/size][size=2][color=#0000ff]Function[/color][/size][size=2] SendMessage( _
[/size][size=2][color=#0000ff]    ByVal[/color][/size][size=2] hWnd [/size][size=2][color=#0000ff]As[/color][/size][size=2] HandleRef, _
[/size][size=2][color=#0000ff]    ByVal[/color][/size][size=2] msg [/size][size=2][color=#0000ff]As[/color][/size][size=2] Int32, _
[/size][size=2][color=#0000ff]    ByVal[/color][/size][size=2] wParam [/size][size=2][color=#0000ff]As[/color][/size][size=2] Int32, _
[/size][size=2][color=#0000ff]    ByRef[/color][/size][size=2] lParam [/size][size=2][color=#0000ff]As[/color][/size][size=2] PARAFORMAT2) [/size][size=2][color=#0000ff]As[/color][/size][size=2] Int32
[/size][size=2][color=#0000ff]End [/color][/size][size=2][color=#0000ff]Function
 
[/color][/size][size=2][color=#0000ff]Private [/color][/size][size=2][color=#0000ff]Const[/color][/size][size=2] EM_GETPARAFORMAT = 1085
[/size][size=2][color=#0000ff]Private [/color][/size][size=2][color=#0000ff]Const[/color][/size][size=2] EM_SETPARAFORMAT = 1095
[/size][size=2][color=#0000ff]Private [/color][/size][size=2][color=#0000ff]Const[/color][/size][size=2] PFM_NUMBERING [/size][size=2][color=#0000ff]As[/color][/size][size=2] Int32 = &H20
[/size][size=2][color=#0000ff]Private [/color][/size][size=2][color=#0000ff]Const[/color][/size][size=2] BULLET_NUMBER = 2[/size]
[size=2] [/size]
[size=2] 
[/size][size=2][color=#0000ff]Private [/color][/size][size=2][color=#0000ff]Sub[/color][/size][size=2] Button1_Click([/size][size=2][color=#0000ff]ByVal[/color][/size][size=2] sender [/size][size=2][color=#0000ff]As[/color][/size][size=2] System.Object, [/size][size=2][color=#0000ff]ByVal[/color][/size][size=2] e [/size][size=2][color=#0000ff]As[/color][/size][size=2] System.EventArgs) [/size][size=2][color=#0000ff]Handles[/color][/size][size=2] Button1.Click[/size]
[size=2] 
[/size][size=2][color=#0000ff]    Dim[/color][/size][size=2] param [/size][size=2][color=#0000ff]As[/color][/size][size=2][color=#0000ff]New[/color][/size][size=2] PARAFORMAT2[/size]
[size=2] 
[/size][size=2][color=#008000]    '/// you must specify the size of the structure here, using Marshal.SizeOf , in VB6 it was Len( )[/color][/size]
[size=2][color=#008000] 
[/color][/size][size=2]    [color=black]param.cbSize = Marshal.SizeOf(param)[/color][/size]
[size=2] 
[/size][size=2][color=#008000]    '/// build up the param structure with the current layout...[/color][/size]
[size=2][color=#008000] 
[/color][/size][size=2]    [color=black]SendMessage([/color][/size][size=2][color=#0000ff]New[/color][/size][size=2] [color=black]HandleRef(rtb, rtb.Handle), EM_GETPARAFORMAT, 0, param)[/color][/size]
[size=2] 
[/size][size=2][color=#008000]    '/// wNumbering[/color][/size]
[size=2][color=#008000] 
[/color][/size][size=2][color=#008000]    '/// Options used for bulleted or numbered paragraphs. To use this member, set the PFM_NUMBERING flag in the dwMask member.[/color][/size]
[size=2][color=#008000] 
[/color][/size][size=2][color=#008000]    '/// PFN_BULLET ( 1 ) = Insert a bullet at the beginning of each selected paragraph[/color][/size]
[size=2][color=#008000] 
[/color][/size][size=2][color=#008000]    '/// 2 = Uses Arabic numbers (1, 2, 3, ...). , hence BULLET_NUMBER.[/color][/size]
[size=2][color=#008000] 
[/color][/size][size=2]    [color=black]param.dwMask = PFM_NUMBERING[/color]
    [color=black]param.wNumbering = BULLET_NUMBER[/color]
 
[/size][size=2][color=#008000]    '/// update the richtextbox...
[/color][/size][size=2]    [/size]
[size=2]    [color=black]SendMessage([/color][/size][size=2][color=#0000ff]New[/color][/size][size=2] [color=black]HandleRef(rtb, rtb.Handle), EM_SETPARAFORMAT, 0, param)[/color][/size]
[size=2] 
[/size][size=2][color=#0000ff]End [/color][/size][size=2][color=#0000ff]Sub[/color][/size]
[/size][size=2][color=#0000ff]
[/color][/size]
 
Last edited:
Thanks for the example dynamic_sysop, I'll use it if I can work out how to convert it to C# :)

Could you advise me on that? Thanks again!
 
sure
smile.gif

C#:
[StructLayout(LayoutKind.Sequential)]
public struct PARAFORMAT2
{
    public Int32 cbSize;
    public Int32 dwMask;
    public Int16 wNumbering;
    public Int16 wReserved;
    public IntPtr dxStartIndent;
    public IntPtr dxRightIndent;
    public IntPtr dxOffset;
    public Int16 wAlignment;
    public short cTabCount;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst =32)]
    public IntPtr[] rgxTabs;
    public IntPtr dySpaceBefore;
    public IntPtr dySpaceAfter;
    public IntPtr dyLineSpacing;
    public short sStyle;
    public byte bLineSpacingRule;
    public byte bOutlineLevel;
    public Int16 wShadingWeight;
    public Int16 wShadingStyle;
    public Int16 wNumberingStart;
    public Int16 wNumberingStyle;
    public Int16 wNumberingTab;
    public Int16 wBorderSpace;
    public Int16 wBorderWidth;
    public Int16 wBorders;
}
 
[DllImport("user32", CharSet = CharSet.Auto)]
private static extern Int32 SendMessage(HandleRef hwnd , Int32 msg , Int32 wparam , ref PARAFORMAT2 lParam);
 
private const int EM_GETPARAFORMAT = 1085;
private const int EM_SETPARAFORMAT = 1095;
private const int PFM_NUMBERING = 0x20;
private const int BULLET_NUMBER = 2 ;
 
private void button1_Click(object sender, System.EventArgs e)
{
    PARAFORMAT2 param = new PARAFORMAT2();
    param.cbSize = Marshal.SizeOf(typeof(PARAFORMAT2));
 
    SendMessage(new HandleRef(richTextBox1, richTextBox1.Handle), EM_GETPARAFORMAT, 0,ref param);
 
    param.dwMask = PFM_NUMBERING;
    param.wNumbering = BULLET_NUMBER;
 
    SendMessage(new HandleRef(richTextBox1, richTextBox1.Handle), EM_SETPARAFORMAT, 0,ref param);
}
 
Bugger, it doesn't work so well. I have to put a tab between the line number and the text or the line numbers get removed, and it only counts up to 254 :(

Perhaps there is another more complecated solution?
 
Back
Top