Problem with line numbers in a RichEdit control using C++ Win32

James Allcock
James Allcock used Ask the Experts™
on
Hi, I'm writing a simple text editor as coding practice in C++ using the Win32 API
and I wanted to add line numbers to the left hand side of the RichEdit control. I
have created a margin by sending a EM_SETMARGINS message to the RichEdit then I
subclassed the RichEdit and responded to the WM_PAINT message. Here's the subclass code :

LRESULT CALLBACK WndEditProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_PAINT:
		{
		CallWindowProc((WNDPROC)OldWndProc, hWnd, message, wParam, lParam);
		HDC hdc = GetDC(hWnd);
		DisplayLineNumbers(hdc);
		ReleaseDC(hWnd, hdc);
		return 0;
		}
		break;
	case WM_DESTROY:
		SetWindowLong(hEdit, GWL_WNDPROC, (LONG)OldWndProc);
		break;
	}

	return CallWindowProc((WNDPROC)OldWndProc, hWnd, message, wParam, lParam);
}

Open in new window


As you can see I called the old window procedure first and then called my DisplayLineNumbers
function coz it didn't work properly if DisplayLineNumbers was called then the old window
procedure was called. But I have a problem with my DisplayLineNumbers function and I'm
not sure how to fix it. It seems to work but when I open a big file then scroll to the end
of the file the line numbers don't line up to the line of the RichEdit and when I hit enter
at the bottom of the file the line numbers skip a few. I must stress that I am a novice
coder so don't expect the code to be perfect but here's the DisplayLineNumbers function
that I wrote (hEdit is the handle of the RichEdit and hFont is the handle of the font and
it accepts a DC for the RichEdit, szBuffer is a buffer for the line number text) :

VOID DisplayLineNumbers(HDC EditDC)
{
	// get first visible line
	INT first_visible = SendMessage(hEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
	first_visible++;

	RECT rc;
	GetClientRect(hEdit, &rc);

	POINT pnt;
	pnt.x = 0;
	pnt.y = rc.bottom;

	// get last visible line
	INT char_index = SendMessage(hEdit, EM_CHARFROMPOS, 0, (LPARAM)&pnt);
	INT last_visible = SendMessage(hEdit, EM_EXLINEFROMCHAR, 0, char_index);
	last_visible++;

	// create bitmap (50 is the width of the bitmap)
	HDC newDC = CreateCompatibleDC(EditDC);
	HBITMAP hBitmap = CreateCompatibleBitmap(EditDC, 50, rc.bottom);
	HANDLE hOldBitmap = SelectObject(newDC, hBitmap);
	
	rc.right = 50;

	// fix the colour of the bitmap
	HBRUSH hBrush = CreateSolidBrush(RGB(192, 192, 192));
	FillRect(newDC, &rc, hBrush);
	DeleteObject(hBrush);

	// set text color and select font
	SetTextColor(newDC, RGB(0, 0, 0));
	SetBkMode(newDC, TRANSPARENT);
	HANDLE hOldFont = SelectObject(newDC, hFont);

	// get height of the selected font
	TEXTMETRIC tm;
	GetTextMetrics(newDC, &tm);

	// draw line numbers to bitmap
	for (INT index = first_visible; index <= last_visible; ++index)
	{
		INT len = wsprintf((LPWSTR)&szBuffer, L"%d", index);
		DrawText(newDC, (LPCWSTR)szBuffer, len, &rc, DT_CENTER | DT_SINGLELINE);
		rc.top = rc.top + tm.tmHeight;
	}

	// bitblt bitmap dc to richedit dc
	BitBlt(EditDC, 0, 0, 50, rc.bottom, newDC, 0, 0, SRCCOPY);

	// clean up
	SelectObject(newDC, hOldFont);
	SelectObject(newDC, hOldBitmap);
	DeleteObject(hBitmap);
	DeleteDC(newDC);

	return;
}

Open in new window


I just can't seem to figure it out so any help would be much appreciated. Like I said
before though I am a beginner at coding so sorry if the answer is a simple one.

Cheers
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial