Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. Integral Number of Lines in RichTextBox

Integral Number of Lines in RichTextBox

Scheduled Pinned Locked Moved C#
tutorialgraphicshelpquestion
9 Posts 2 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    Andrew Shapira
    wrote on last edited by
    #1

    Hello, How can one set up a RichTextBox so that the box shows an integral number of text lines, say 17, when the text box is scrolled all the way down? Possibly this would involve making the RichTextBox have a particular size. The example below shows what I tried: set ClientSize.Height to be a multiple of Font.Height. It didn't work. When the text box is scrolled all the way down, a piece of a line shows at the top, which looks bad. I don't know how to calculate the amount by which the sizing is off. (This rich text box will always be scrolled all the way down. Thanks to posters who responded to "help me, how to autoscroll in richtextbox" by KETUINHA for showing me how to do this.) By the way, how can one post code in these forums and have the code's indentation be preserevd? Using 'code' tags ended up with no indentation, at least according to the preview. using System; using System.Drawing; using System.Text; using System.Windows.Forms; class TextBoxTesterForm : Form { public TextBoxTesterForm() { int lines = 5; d_rtb = new RichTextBox(); d_rtb.SuspendLayout(); d_rtb.Parent = this; d_rtb.Location = new Point(10,10); int desiredTextHeight = lines * d_rtb.Font.Height; d_rtb.ClientSize = new Size(200, desiredTextHeight); d_rtb.ResumeLayout(); Console.WriteLine("lines={0}", lines); Console.WriteLine("rtb Font.Height = {0}", d_rtb.Font.Height); Console.WriteLine("rtb Font.GetHeight() = {0}", d_rtb.Font.GetHeight()); Console.WriteLine("desiredTextHeight = {0}", desiredTextHeight); Console.WriteLine("rtb ClientSize = {0}", d_rtb.ClientSize); Console.WriteLine("rtb DisplayRectangle = {0}", d_rtb.DisplayRectangle); Console.WriteLine("rtb Size = {0}", d_rtb.Size); Console.WriteLine("rtb Multiline = {0}", d_rtb.Multiline); } RichTextBox d_rtb; } class TextBoxTestMain { static void Main() { Application.Run(new TextBoxTesterForm()); } }

    B 1 Reply Last reply
    0
    • A Andrew Shapira

      Hello, How can one set up a RichTextBox so that the box shows an integral number of text lines, say 17, when the text box is scrolled all the way down? Possibly this would involve making the RichTextBox have a particular size. The example below shows what I tried: set ClientSize.Height to be a multiple of Font.Height. It didn't work. When the text box is scrolled all the way down, a piece of a line shows at the top, which looks bad. I don't know how to calculate the amount by which the sizing is off. (This rich text box will always be scrolled all the way down. Thanks to posters who responded to "help me, how to autoscroll in richtextbox" by KETUINHA for showing me how to do this.) By the way, how can one post code in these forums and have the code's indentation be preserevd? Using 'code' tags ended up with no indentation, at least according to the preview. using System; using System.Drawing; using System.Text; using System.Windows.Forms; class TextBoxTesterForm : Form { public TextBoxTesterForm() { int lines = 5; d_rtb = new RichTextBox(); d_rtb.SuspendLayout(); d_rtb.Parent = this; d_rtb.Location = new Point(10,10); int desiredTextHeight = lines * d_rtb.Font.Height; d_rtb.ClientSize = new Size(200, desiredTextHeight); d_rtb.ResumeLayout(); Console.WriteLine("lines={0}", lines); Console.WriteLine("rtb Font.Height = {0}", d_rtb.Font.Height); Console.WriteLine("rtb Font.GetHeight() = {0}", d_rtb.Font.GetHeight()); Console.WriteLine("desiredTextHeight = {0}", desiredTextHeight); Console.WriteLine("rtb ClientSize = {0}", d_rtb.ClientSize); Console.WriteLine("rtb DisplayRectangle = {0}", d_rtb.DisplayRectangle); Console.WriteLine("rtb Size = {0}", d_rtb.Size); Console.WriteLine("rtb Multiline = {0}", d_rtb.Multiline); } RichTextBox d_rtb; } class TextBoxTestMain { static void Main() { Application.Run(new TextBoxTesterForm()); } }

      B Offline
      B Offline
      Blake Coverett
      wrote on last edited by
      #2

      Use the <pre> tag for posting code with indentations, and go read Raymond's blog for _everything_ you ever wanted to know about scrolling and were afraid to ask. An eleven part series on all the intricacies. -- -Blake (com/bcdev/blake)

      A 1 Reply Last reply
      0
      • B Blake Coverett

        Use the <pre> tag for posting code with indentations, and go read Raymond's blog for _everything_ you ever wanted to know about scrolling and were afraid to ask. An eleven part series on all the intricacies. -- -Blake (com/bcdev/blake)

        A Offline
        A Offline
        Andrew Shapira
        wrote on last edited by
        #3

        Thanks. I glanced at Raymond's blog. Before I search through it in detail for the iota I'm looking for, can you tell me why you think this has something to do with scroll bars?

        B 1 Reply Last reply
        0
        • A Andrew Shapira

          Thanks. I glanced at Raymond's blog. Before I search through it in detail for the iota I'm looking for, can you tell me why you think this has something to do with scroll bars?

          B Offline
          B Offline
          Blake Coverett
          wrote on last edited by
          #4

          Because, despite the scrollbars title, it's about a lot more. Have a look at parts 7 & 8 in particular, titled "Integrality" and "Integral interactive resizing" respectively. -- -Blake (com/bcdev/blake)

          B A 2 Replies Last reply
          0
          • B Blake Coverett

            Because, despite the scrollbars title, it's about a lot more. Have a look at parts 7 & 8 in particular, titled "Integrality" and "Integral interactive resizing" respectively. -- -Blake (com/bcdev/blake)

            B Offline
            B Offline
            Blake Coverett
            wrote on last edited by
            #5

            And here's a chunk of code that does exactly what you are looking for with a pair of RichEdit controls separated by a splitter. Digging out the bit that applies to just the top RichEdit is left as an exercise to the reader. Warning - old Win32 code, no MFC, no WTL, no CLR, just C++/Win32. The math however is still the same.

            void CConsole::ReSize(int *pcx, int *pcy, BOOL bSnap)
            {
            int cx = GetSystemMetrics(SM_CXEDGE);
            int cy = GetSystemMetrics(SM_CYEDGE);
            int nScrollWidth = GetSystemMetrics(SM_CXVSCROLL) +
            GetSystemMetrics(SM_CXBORDER);
            int nSepHeight = GetSystemMetrics(SM_CYFIXEDFRAME);

            RECT r;
            SendMessage(m\_hOutput, EM\_GETRECT, 0, LPARAM(&r));
            cx += r.left;
            cy += r.top;
            
            if (pcx && pcx) {
            	if (bSnap) {
            		RECT r;
            		r.top = r.left = 0;
            		r.right = m\_nCols \* m\_nCharWidth + 2 \* cx + nScrollWidth;
            		r.bottom = (m\_nOutputRows + m\_nInputRows) \* m\_nCharHeight + 4 \* cy 
            			+ nSepHeight + m\_nStatusHeight;
            		AdjustWindowRectEx(&r, GetWindowLong(m\_hWnd, GWL\_STYLE), 
            			BOOL(GetMenu(m\_hWnd)), GetWindowLong(m\_hWnd, GWL\_EXSTYLE));
            		\*pcx = r.right - r.left;
            		\*pcy = r.bottom - r.top;
            	} else {
            		int cxClient = \*pcx, cyClient = \*pcy;
            		RECT r;
            		r.left = 0; r.top = 0;
            		r.right = \*pcx; r.bottom = \*pcy;
            		AdjustWindowRectEx(&r, GetWindowLong(m\_hWnd, GWL\_STYLE), 
            			BOOL(GetMenu(m\_hWnd)), GetWindowLong(m\_hWnd, GWL\_EXSTYLE));
            		int cxOld = cxClient -= r.right - r.left - \*pcx;
            		int cyOld = cyClient -= r.bottom - r.top - \*pcy;
            
            		m\_nCols = max(0, (cxClient - 2 \* cx - nScrollWidth
            			+ m\_nCharWidth / 2) / m\_nCharWidth);
            		cxClient = m\_nCols \* m\_nCharWidth + 2 \* cx + nScrollWidth;
            
            		int nTotalRows = max(0, (cyClient - 4 \* cy - nSepHeight 
            			- m\_nStatusHeight + m\_nCharHeight / 2) / m\_nCharHeight);
            		cyClient = nTotalRows \* m\_nCharHeight + 4 \* cy 
            			+ nSepHeight + m\_nStatusHeight;
            
            		m\_nOutputRows = nTotalRows - m\_nInputRows;
            		if (m\_nOutputRows < 0) {
            			m\_nInputRows += m\_nOutputRows;
            			m\_nOutputRows = 0;
            		}
            
            		\*pcx += cxClient - cxOld;
            		\*pcy += cyClient - cyOld;
            	}
            }
            
            HDWP hdwp = BeginDeferWindowPos(3);
            hdwp = DeferWindowPos(hdwp, m\_hOutput, NULL, 0, 0, 
            	m\_nCols \* m\_nCharWidth + 2 \* cx + nScrollWidth, 
            	m\_nOutputRows \* m\_nCharHeight + 2 \* cy, 
            	SWP\_NOACTIVATE | SWP\_NOZORDER);
            hdwp = DeferWindowPos(hdwp, m\_hInput, NULL, 0, 
            	m\_nOutputRows \* m\_nCharHeight + 2 \* cy + nSepHeight, 
            	m\_nCols \* m\_nCharWidth + 2 \* cx + nScrollWidth,
            	m\_nInputRows \* m\_nCharHeight + 2 \* cy, 
            	SWP\_NOACTIVATE | SWP\_NOZORDER);
            
            A 1 Reply Last reply
            0
            • B Blake Coverett

              Because, despite the scrollbars title, it's about a lot more. Have a look at parts 7 & 8 in particular, titled "Integrality" and "Integral interactive resizing" respectively. -- -Blake (com/bcdev/blake)

              A Offline
              A Offline
              Andrew Shapira
              wrote on last edited by
              #6

              Ah. Well, thanks, I took a look. I don't know the Win API but it appears that the idea in the blog is to compute the difference between the vertical extents of the window and the client area, and use the difference to adjust the size of the window so that the client area comes out to be an integral number of text lines. In the example I gave, getting the client area to be a desired size is not the problem. The desired vertical size of the client area is 110 pixels, and that is what the area is as measured with a screen dump. It appears that setting the ClientSize property of the rich text box to use a height of 110 does in fact set the client area to 110. So I think the blog might be solving a different problem than what's needed here. One problem I did notice is that the font's Font.Height value is given as 22 pixels, but the baseline-to-baseline spacing in the rich text box is 24 pixels. Does anyone know why this might be? It's certainly necessary to account for this in order to get an integral number of text lines. Maybe there is some Font or RichTextBox property that needs to be used besides Font.Height.

              1 Reply Last reply
              0
              • B Blake Coverett

                And here's a chunk of code that does exactly what you are looking for with a pair of RichEdit controls separated by a splitter. Digging out the bit that applies to just the top RichEdit is left as an exercise to the reader. Warning - old Win32 code, no MFC, no WTL, no CLR, just C++/Win32. The math however is still the same.

                void CConsole::ReSize(int *pcx, int *pcy, BOOL bSnap)
                {
                int cx = GetSystemMetrics(SM_CXEDGE);
                int cy = GetSystemMetrics(SM_CYEDGE);
                int nScrollWidth = GetSystemMetrics(SM_CXVSCROLL) +
                GetSystemMetrics(SM_CXBORDER);
                int nSepHeight = GetSystemMetrics(SM_CYFIXEDFRAME);

                RECT r;
                SendMessage(m\_hOutput, EM\_GETRECT, 0, LPARAM(&r));
                cx += r.left;
                cy += r.top;
                
                if (pcx && pcx) {
                	if (bSnap) {
                		RECT r;
                		r.top = r.left = 0;
                		r.right = m\_nCols \* m\_nCharWidth + 2 \* cx + nScrollWidth;
                		r.bottom = (m\_nOutputRows + m\_nInputRows) \* m\_nCharHeight + 4 \* cy 
                			+ nSepHeight + m\_nStatusHeight;
                		AdjustWindowRectEx(&r, GetWindowLong(m\_hWnd, GWL\_STYLE), 
                			BOOL(GetMenu(m\_hWnd)), GetWindowLong(m\_hWnd, GWL\_EXSTYLE));
                		\*pcx = r.right - r.left;
                		\*pcy = r.bottom - r.top;
                	} else {
                		int cxClient = \*pcx, cyClient = \*pcy;
                		RECT r;
                		r.left = 0; r.top = 0;
                		r.right = \*pcx; r.bottom = \*pcy;
                		AdjustWindowRectEx(&r, GetWindowLong(m\_hWnd, GWL\_STYLE), 
                			BOOL(GetMenu(m\_hWnd)), GetWindowLong(m\_hWnd, GWL\_EXSTYLE));
                		int cxOld = cxClient -= r.right - r.left - \*pcx;
                		int cyOld = cyClient -= r.bottom - r.top - \*pcy;
                
                		m\_nCols = max(0, (cxClient - 2 \* cx - nScrollWidth
                			+ m\_nCharWidth / 2) / m\_nCharWidth);
                		cxClient = m\_nCols \* m\_nCharWidth + 2 \* cx + nScrollWidth;
                
                		int nTotalRows = max(0, (cyClient - 4 \* cy - nSepHeight 
                			- m\_nStatusHeight + m\_nCharHeight / 2) / m\_nCharHeight);
                		cyClient = nTotalRows \* m\_nCharHeight + 4 \* cy 
                			+ nSepHeight + m\_nStatusHeight;
                
                		m\_nOutputRows = nTotalRows - m\_nInputRows;
                		if (m\_nOutputRows < 0) {
                			m\_nInputRows += m\_nOutputRows;
                			m\_nOutputRows = 0;
                		}
                
                		\*pcx += cxClient - cxOld;
                		\*pcy += cyClient - cyOld;
                	}
                }
                
                HDWP hdwp = BeginDeferWindowPos(3);
                hdwp = DeferWindowPos(hdwp, m\_hOutput, NULL, 0, 0, 
                	m\_nCols \* m\_nCharWidth + 2 \* cx + nScrollWidth, 
                	m\_nOutputRows \* m\_nCharHeight + 2 \* cy, 
                	SWP\_NOACTIVATE | SWP\_NOZORDER);
                hdwp = DeferWindowPos(hdwp, m\_hInput, NULL, 0, 
                	m\_nOutputRows \* m\_nCharHeight + 2 \* cy + nSepHeight, 
                	m\_nCols \* m\_nCharWidth + 2 \* cx + nScrollWidth,
                	m\_nInputRows \* m\_nCharHeight + 2 \* cy, 
                	SWP\_NOACTIVATE | SWP\_NOZORDER);
                
                A Offline
                A Offline
                Andrew Shapira
                wrote on last edited by
                #7

                Blake, that code uses a variable called m_nCharHeight that is not defined in the code. How is the value of this variable computed?

                B 1 Reply Last reply
                0
                • A Andrew Shapira

                  Blake, that code uses a variable called m_nCharHeight that is not defined in the code. How is the value of this variable computed?

                  B Offline
                  B Offline
                  Blake Coverett
                  wrote on last edited by
                  #8

                  It's just a cached copy of the tmHeight height value from the TEXTMETRIC for the currently selected font. Here's the relevent bit out of the middle of an EnumFontFamilies callback:

                  	HDC hdc = GetDC(NULL)
                  	LOGFONT lf = pelf->elfLogFont;
                  	lf.lfHeight = -MulDiv(pParam->pCon->m\_nPointSize, 
                  		GetDeviceCaps(hdc, LOGPIXELSY), 72),
                  	lf.lfWidth = 0;
                  	HFONT hf = CreateFontIndirect(&lf);
                  
                  	TEXTMETRIC tm;
                  	HFONT hfOld = (HFONT)SelectObject(hdc, hf);
                  	GetTextMetrics(hdc, &tm);
                  	SelectObject(hdc, hfOld);
                  	ReleaseDC(NULL, hdc);
                  	
                  	SendMessage(pParam->pCon->m\_hOutput, WM\_SETFONT, WPARAM(hf), 0);
                  	SendMessage(pParam->pCon->m\_hInput, WM\_SETFONT, WPARAM(hf), 0);
                  	DeleteObject(hf);
                  
                  	pParam->pCon->m\_nCharWidth = tm.tmAveCharWidth;
                  	pParam->pCon->m\_nCharHeight = tm.tmHeight;
                  

                  -- -Blake (com/bcdev/blake)

                  A 1 Reply Last reply
                  0
                  • B Blake Coverett

                    It's just a cached copy of the tmHeight height value from the TEXTMETRIC for the currently selected font. Here's the relevent bit out of the middle of an EnumFontFamilies callback:

                    	HDC hdc = GetDC(NULL)
                    	LOGFONT lf = pelf->elfLogFont;
                    	lf.lfHeight = -MulDiv(pParam->pCon->m\_nPointSize, 
                    		GetDeviceCaps(hdc, LOGPIXELSY), 72),
                    	lf.lfWidth = 0;
                    	HFONT hf = CreateFontIndirect(&lf);
                    
                    	TEXTMETRIC tm;
                    	HFONT hfOld = (HFONT)SelectObject(hdc, hf);
                    	GetTextMetrics(hdc, &tm);
                    	SelectObject(hdc, hfOld);
                    	ReleaseDC(NULL, hdc);
                    	
                    	SendMessage(pParam->pCon->m\_hOutput, WM\_SETFONT, WPARAM(hf), 0);
                    	SendMessage(pParam->pCon->m\_hInput, WM\_SETFONT, WPARAM(hf), 0);
                    	DeleteObject(hf);
                    
                    	pParam->pCon->m\_nCharWidth = tm.tmAveCharWidth;
                    	pParam->pCon->m\_nCharHeight = tm.tmHeight;
                    

                    -- -Blake (com/bcdev/blake)

                    A Offline
                    A Offline
                    Andrew Shapira
                    wrote on last edited by
                    #9

                    What is the equivalent quantity in managed .NET (perhaps accessible through the Font class)?

                    1 Reply Last reply
                    0
                    Reply
                    • Reply as topic
                    Log in to reply
                    • Oldest to Newest
                    • Newest to Oldest
                    • Most Votes


                    • Login

                    • Don't have an account? Register

                    • Login or register to search.
                    • First post
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • World
                    • Users
                    • Groups