//----------------------------------------------------------------------------- // AppendToLogAndScroll() /// /// \brief Add a string to the serial log window at the current position, /// then scroll to the end of the text such that the last line of /// the text is shown at the bottom of the CRichEditCtrl. /// /// The string is added to the message log starting at the current position, /// i.e. without starting a new line. Then the control scrolls down to show /// as much text as possible, including the last line of text at the very /// bottom. /// The string is displayed in the specified text color. /// The string may be a multiline string using carriage return/line feed /// (i.e. newline) characters to indicate a line breaks. /// /// \param [in] str The string to add to the message log. /// \param [in] color The text color of the string. You may use the /// RGB(r,g,b) macro to specify the color byte-wise. /// \return An integer indicating sucess or failure: /// - 0, if the function succeeded. /// - (-1), if the function failed. /// (This function always returns 0, because no /// parameter or failure checking is done.) /// /// \remark /// The automatic scrolling function would be easy, if the MFC documentation /// was correct. Unfortunetely, it is not as trivial as one might think. /// If the CRichEditCtrl has the focus, it scrolls automatically if you /// insert text programatically. If it does not have the focus, it does not /// scroll automatically, so in that case you can use the LineScroll() /// method and you get the results you would expect when reading the MFC docs. /// This is true even if ES_AUTOxSCROLL style is NOT set. /// /// So the point is to check in the AppendToLogAndScroll() method if the /// affected CRichEditCtrl has the focus. If so, we must not call /// LineScroll(). If not, it is safe to call LineSroll() to first scroll to /// the very end, which means that the last line of text is shown at the top /// of the CRichEditCtrl. /// Then we call LineScroll() a second time, this time scrolling back by /// the number of visible lines. This leads to having the last line of the /// text being displayed at the bottom of CRichEditCtrl. /// /// Please note that in this sample application, the CRichEditCtrl never has /// the focus, because we always have to click a button in order to insert /// text. However, if you are using the code in an application not based on /// a dialog and that fills up the control where the user could have set focus /// to the control first, this method would fail to scroll correctly without /// checking the focus. /// I used this code in an MDI application, and there the control claims /// to have the focus if I click into the control before clicking a menu /// command (whatever the reason might be why in that case the focus is /// not lost to the menu command). /// /// Please note that the code is written for maximum comprehension / good /// readability, not for code or execution efficiency. //----------------------------------------------------------------------------- int CThreadTestDlg::AppendToLogAndScroll( CString str, COLORREF color ) { long nVisible = 0; long nInsertionPoint = 0; CHARFORMAT cf; // Initialize character format structure cf.cbSize = sizeof( CHARFORMAT ); cf.dwMask = CFM_COLOR | CFM_SIZE; cf.dwEffects = 0; // To disable CFE_AUTOCOLOR cf.yHeight = 210; // 1twips = 15px, 近似使用五号字体 cf.crTextColor = color; // Set insertion point to end of text nInsertionPoint = m_ctrlLog.GetWindowTextLength(); m_ctrlLog.SetSel( nInsertionPoint, -1 ); // Set the character format m_ctrlLog.SetSelectionCharFormat( cf ); // Replace selection. Because we have nothing // selected, this will simply insert // the string at the current caret position. m_ctrlLog.ReplaceSel( str ); // Get number of currently visible lines or maximum number of visible lines // (We must call GetNumVisibleLines() before the first call to LineScroll()!) nVisible = GetNumVisibleLines( &m_ctrlLog ); // Now this is the fix of CRichEditCtrl's abnormal behaviour when used // in an application not based on dialogs. Checking the focus prevents // us from scrolling when the CRichEditCtrl does so automatically, // even though ES_AUTOxSCROLL style is NOT set. if ( &m_ctrlLog != m_ctrlLog.GetFocus() ) { m_ctrlLog.LineScroll( INT_MAX ); m_ctrlLog.LineScroll( 1 - nVisible ); } return 0; }
void CLogPid::DisplayData (LPCTSTR pszData) { long nVisible = 0; if (m_bPause) return; // Format the selection as default text CHARFORMAT cf; cf.cbSize = sizeof(cf); cf.dwMask = CFM_COLOR; m_ctrlLog.GetSelectionCharFormat(cf); cf.dwEffects |= CFE_AUTOCOLOR; cf.yHeight = 183; strcpy( cf.szFaceName, FONT_NAME ); m_ctrlLog.SetSelectionCharFormat(cf); // Add the event to the edit control m_ctrlLog.SetSel(-1,-1); m_ctrlLog.ReplaceSel(pszData); // Get number of currently visible lines or maximum number of visible lines // (We must call GetNumVisibleLines() before the first call to LineScroll()!) nVisible = GetNumVisibleLines(&m_ctrlLog); // Now this is the fix of CRichEditCtrl's abnormal behaviour when used // in an application not based on dialogs. Checking the focus prevents // us from scrolling when the CRichEditCtrl does so automatically, // even though ES_AUTOxSCROLL style is NOT set. if (&m_ctrlLog != m_ctrlLog.GetFocus()) { m_ctrlLog.LineScroll(INT_MAX); m_ctrlLog.LineScroll(1 - nVisible); } }