zoukankan      html  css  js  c++  java
  • CHtmlEditCtrl (2): Add a Source Text Editor to Your HTML Editor

    In a previous article, I described how to create an HTML editor using the MFC CHtmlEditCtrl class in a dialog box.  It could be used for creating "rich text" emails, chat-box composition, or perhaps even as an option for a syntax-highlighting code editor -- anywhere you would like to show HTML and let the user modify it.

    As the picture shows, we're going to add a source-text edit box so that you can make manual changes to the HTML source text -- giving you a way to explore some new options for this powerful control.

    Use the Visual Studio Dialog Editor to add a multi-line Edit Control below the static text "placeholder" for the HTML editor.  Right-click it and Add a control-type variable to the parent dialog (m_ctHtmlSrcText).

    Add this to the OnBnClickedLoadfile() function:

    m_ctHtmlSrcText.SetWindowTextW( m_sHtml ); // populate the Editbox

     

    Now, wouldn't it be cool if we could update the source text box whenever the user made changes in the HTML editor?  Alas, there is no "OnChange" type notification from the control, so that's the next challenge: I needed to find a way to determine when the user has made a change in the HTML editor.  I looked at the GetIsDirty() function, but that flag gets set right after the first edit and there's no clean way to set it back after an update from the source text -- so I went with a different approach...

    I decided to set up a window timer and use it to compare the most recently-copied HTML to the current HTML.  If it varies, then I re-populate the source text edit box, making sure to re-display it at the earlier scroll position.

    And of course, we want to do a similar thing when the user modifies the HTML source text -- update the browser view with the changes.  Here's the code for all of that:

    //------------------------------------------------

    // update the HTML source box with changes from HTML Editor

    //

    void CEditHtmlDlg::SyncSrcToHtml()

    {

        m_ctlEditHtml.GetDocumentHTML( m_sHtml );

        int nLine= m_ctHtmlSrcText.GetFirstVisibleLine(); // remember cur pos

        m_ctHtmlSrcText.LockWindowUpdate(); // avoid some flashing

        m_ctHtmlSrcText.SetWindowTextW( m_sHtml );

        m_ctHtmlSrcText.LineScroll(nLine, 0);

        m_ctHtmlSrcText.UnlockWindowUpdate();

        m_fSrcNeedsSync= false;

    }

    //------------------------------------------------

    // update the Browser view changes from source text box

    void CEditHtmlDlg::SyncHtmlToSrc()

    {

        //------- all this to locate the scroll position...

        long nOffsetTop;

        IHTMLDocument2* pDoc;

        BOOL fRet= m_ctlEditHtml.GetDHtmlDocument( &pDoc );

        IHTMLElement* pBody;

        pDoc->get_body( &pBody );

        IHTMLElement2* pBody2;

        pBody->QueryInterface (IID_IHTMLElement2, (void**)&pBody2);

        pBody2->get_scrollTop( &nOffsetTop );

     

        //------- update the HTML

        m_ctHtmlSrcText.GetWindowTextW( m_sHtml );

        m_ctlEditHtml.SetDocumentHTML( m_sHtml );

        m_ctlEditHtml.LockWindowUpdate(); // avoid some flashing

        AwaitReady( 2 ); // CHtmlEditCtrl takes time for "document complete"

        //------- now scroll back to saved position

        IHTMLWindow2* pWin;

        pDoc->get_parentWindow( &pWin );

        pWin->scrollTo(0,nOffsetTop);

        m_ctlEditHtml.UnlockWindowUpdate();

     

        m_fHtmlNeedsSync= false;

    }

     

    Updating the source text window was basically a no-brainer, but handling the HTML editor update was a bit trickier.  Re-loading the HTML into the CHtmlEditCtrl causes it to redisplay at the top -- a very rude thing to do to a user.  I had to use the IHTMLElement2 get_scrollTop for the document body to obtain the current scroll position and the IHTMLWindow2 scrollTo function to restore it after reloading the HTML.

    I found that without the call to AwaitReady (in line 32), the scrollTo function was ignored -- the embedded browser control needs a short time to reprocess the HTML.  So I used a technique from an 
    earlier article to delay processing until the control indicates it is ready.  You'll find the AwaitReady() function in the project source code available for download at the end of this article.

    In the Dialog Editor, right-click the source text edit control and use Add Event Handler... to create an OnEnChange handler to the dialog class.

    Here's the OnTimer function and the CEdit's EN_CHANGE notification handler that use the SyncXxxxx functions:

    void CEditHtmlDlg::OnEnChangeHtmlsrc()

    {

        m_dwLastEnChangeTick= GetTickCount();        

        m_fHtmlNeedsSync= true;

    }

    //--------------------------------------------

    // I used a StartTimer() in OnInit Dialog

    // to execute this 10 times per second

    //

    void CEditHtmlDlg::OnTimer(UINT_PTR nIDEvent)

    {

        if ( m_fSrcNeedsSync ) {

            SyncSrcToHtml(); // update source view, set m_fSrcNeedsSync false

        }

        else { // check to see if HTML has changed

            CString sCurHtml;

            m_ctlEditHtml.GetDocumentHTML( sCurHtml );

            if ( sCurHtml != m_sHtml ) {

                m_sHtml= sCurHtml;

                m_fSrcNeedsSync= true; // update on next pass through

            }

        }

        if ( m_fHtmlNeedsSync ) {

            // here, we wait until the user stops typing (1 second)...

            if( GetTickCount() > m_dwLastEnChangeTick + M_MsDelayBeforeUpdate ) {

                SyncHtmlToSrc(); // update HTML view, set m_fHtmlNeedsSync false

            }

        }

        CDialog::OnTimer(nIDEvent);

    }

     

    Some notes on the above code:

     I added:
             SetTimer( M_UpdateTimerID, 100, 0 );
    to my OnInitDialog function, and used the Class Wizard to add the WM_TIMER handler.  Thus, the OnTimer function executes 10 times per second.

     

     Line 18 looks like it might be a problem -- ten times per second, the code fetches the HTML source text form the CHtmlEditCtrl and compares it to the previously-saved text.  That seems like a lot of processing.  However, most HTML files are relatively short and CPUs are fast.  As a pragmatic test, even when I tried doing it 100 times per second on a large HTML file, I did not overburden my CPU.  If you want, you can decrease the timer to five times or twice per second.

     

     Line 25 looks at a time-value variable that gets set each time OnEnChangeHtmlsrc gets triggered (e.g., when the user types or pastes or deletes in the source text window).  If less than one second has elapsed since the last such editing change, it does nothing.  The end result is that you can finish your typing without being interrupted.

    Summary:
    We now have a dialog-based (non Doc/View) HTML editor that also displays and lets you modify the source HTML.  It automatically updates one when you modify the other.  We had to work around the lack of an "On Change" notification from CHtmlEditCtrl, but the timer-based solution works well.

    In the 
    next installment, we'll add some functionality to let the user set colors, create bullet lists, and so forth.

    Project Source Code
    The full source code for this project is available for download.  It includes a VS2008 project file.
    EditHtml.zip

    References:

    CHtmlEditCtrl Class
    http://msdn.microsoft.com/en-us/library/h14ht0dh.aspx

    CHtmlEditCtrlBase Class
    http://msdn.microsoft.com/en-us/library/54542c1c.aspx

    MSHTML Editing Overviews and Tutorials
    http://msdn.microsoft.com/en-us/library/aa770039(VS.85).aspx

    IHTMLElement2 Interface
    http://msdn.microsoft.com/en-us/library/aa703984(VS.85).aspx

    IHTMLWindow2 Interface
    http://msdn.microsoft.com/en-us/library/aa741505(VS.85).aspx

    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    If you liked this article and want to see more from 
    this author,  please click the Yes button near the:
          Was this article helpful?
    label that is just below and to the right of this text.   
    Thanks!
    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

    From: https://www.experts-exchange.com/articles/1397/Add-a-Source-Text-Editor-to-Your-HTML-Editor.html

  • 相关阅读:
    LeetCode题解之Flipping an Image
    LeetCode 之Find Minimum in Rotated Sorted Array
    LeetCode题解Transpose Matrix
    LeetCode 题解之Minimum Index Sum of Two Lists
    LeetCode题解之Intersection of Two Linked Lists
    LeetCode 题解之Add Two Numbers II
    LeetCode题解之Add two numbers
    href="#"与href="javascript:void(0)"的区别
    有关ie9 以下不支持placeholder属性以及获得焦点placeholder的移除
    ie7下属性书写不规范造成的easyui 弹窗布局紊乱
  • 原文地址:https://www.cnblogs.com/time-is-life/p/8047353.html
Copyright © 2011-2022 走看看