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

CHtmlEditCtrl (2): Add a Source Text Editor to Your HTML Editor的更多相关文章

  1. iOS - 解决Unable to add a source with url `https://github.com/CocoaPods/Specs.git` named

    1  本来cocopods没有问题,最近创建项目,利用cocopods导入第三方库的时候,出现如下错误: [!] Unable to add a source with url `https://gi ...

  2. CodeMirror动态修改代码(关键: editor.getDoc().setValue(data); editor.refresh();)

    在使用codemirror时,其原理是根据form中的textarea标签,自动加载其内容,获得代码行的显示.(具体使用方式参见 codemirror官网使用手册 http://codemirror. ...

  3. [NOI2003]Editor & [AHOI2006]文本编辑器editor BZOJ1507&BZOJ1269

    分析: Splay区间操作裸题,维护出区间信息,按照要求模拟,注意读入格式,并且考虑内存回收(开不下) 附上代码: #include <cstdio> #include <algor ...

  4. CHtmlEditCtrl (3): More HTML Editor Options

    In this version of our HTML Editor, we'll create a floating source view/edit window and we'll implem ...

  5. CHtmlEditCtrl(1) : Use CHtmlEditCtrl to Create a Simple HTML Editor

    I needed a lightweight HTML editor to generate "rich text" emails, so I decided to explore ...

  6. ggplot2 texts : Add text annotations to a graph in R software

    http://www.sthda.com/english/wiki/ggplot2-texts-add-text-annotations-to-a-graph-in-r-software Instal ...

  7. web & Rich Text Editor

    web & Rich Text Editor 富文本编辑器 http://www.wangeditor.com/ https://github.com/wangfupeng1988/wangE ...

  8. [r]Seven habits of effective text editing

    Seven habits of effective text editing(via) Bram Moolenaar November 2000 If you spend a lot of time ...

  9. JSON Editor 中文文档

    JSON Editor JSON Editor 根据定义的JSON Schema 生成了一个Html 表单来对JSON进行编辑.它完整支持JSON Schema 的版本3和版本4,并且它集成了一些流行 ...

随机推荐

  1. 10 个理由让你继续干 IT

    1.钱,钱,钱 对,我们努力工作就是为了赚钱,而IT专业人士的努力工作的确得到了很好的补偿.报酬不仅仅是好而已,而是非常棒.根据美国劳工部<2010年美国 就业与报酬情况概览>(表6,PD ...

  2. 中国移动CMPP协议、联通SGIP协议、电信SMGP协议短信网关

    移动cmpp协议 英文缩写:CMPP (China Mobile Peer to Peer) 中文名称:中国移动通信互联网短信网关接口协议 说明:为中国移动通信集团公司企业规范.规范中描述了中国移动短 ...

  3. 数据库数据格式化之Kettle Spoon

    前言 现在的数据库种类越来越多,数据库备份的格式也越来越复杂,所以数据格式化一直是一个老生常谈的问题.据库备份文件格式那么多,既有SQL的,也有BAK的,还有TXT的等.数据库种类也有很多,MySQL ...

  4. C#中一种替换switch语句更优雅的写法

    今天在项目中遇到了使用switch语句判断条件,但问题是条件比较多,大概有几十个条件,满屏幕的case判断,是否有更优雅的写法替代switch语句呢? 假设有这样的一个场景:商场经常会根据情况采取不同 ...

  5. ASP.NET MVC与Sql Server交互, 插入数据

    在"ASP.NET MVC与Sql Server建立连接"中,与Sql Server建立了连接.本篇实践向Sql Server中插入数据. 在数据库帮助类中增加插入数据的方法. p ...

  6. C语言控制结构

    C语言流程控制 一.流程控制结构 (1)顺序结构:按书写顺序执行每一条语句. (2)选择结构:对给定的条件进行判断,根据判断结果决定执行哪一段代码. (3)循环结构:在给定条件成立的情况下,反复执行某 ...

  7. 简述 IOS中的LazyLoad思想

    Lazy,谁懒?当然是计算机偷懒.通常用法,你有一个NSArray的property,但是你不在初始化方法里为其alloc/init,它就只是一个指针,不会占用内存.然后你写了此property的访问 ...

  8. CentOS 7 修改时区

    转自:http://blog.csdn.net/robertsong2004/article/details/42268701 本文转载至:http://mathslinux.org/?p=637 L ...

  9. hdu 2049 不easy系列之(4)——考新郎

    不easy系列之(4)--考新郎 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  10. 用开源项目ExpandableTextView打造可以下拉扩展的TextView

    这次还是用开源项目来实现效果,我个人觉得上面的这个效果还是很赞的.于是就记录下如何实现这个效果,其实相当简单.这就是开源项目写的好的例子,整个开源项目的代码十分清晰,逻辑和代码结构都很棒,接入自己的工 ...