Scintilla在WTL中的简易使用 Scintilla 在MFC中的简易使用(动态、静态) 更新 VisualFC 0.82 使其正确列举出所有菜单项 ID

Scintilla在WTL中的简易使用

Scintilla是一个开源的源代码编辑组件。在这里记录下它在WTL中的简易使用。

在 WTL 中使用 Scintilla 的一个比较成功的案例是pnotepadProgrammer's Notepad Development

大家可以访问 http://code.google.com/p/pnotepad/ ,不过其现在代码庞大,阅读有一定难度。

现提供一玩具级的演示示例,如下:

下面将简单介绍在WTLSDI框架下如何使用Scintilla。本文使用的是Scintilla 3.2.5。

1.   下载Scintilla源代码(http://www.scintilla.org/ScintillaDownload.html

编译参照 Scintilla 3.2.5在VC中的编译(动态、静态)

本文使用3.2.5版本

2.新建一WTL SDI项目,如:WtlScintillaSDI


3.(动态、静态) 使用 Scintilla 代码初始化。

在 WtlScintillaSDI.cpp 中添加如下代码:

#ifdef STATIC_BUILD_SCI
#include "Scintilla.h"
#endif
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)
{
#ifdef STATIC_BUILD_SCI
	Scintilla_RegisterClasses( hInstance );
#else
    HMODULE m_hSciLexerDll = NULL;
	m_hSciLexerDll = LoadLibrary(_T("SciLexer.dll"));
	if (NULL == m_hSciLexerDll)
	{
		MessageBox( NULL, _T("LoadLibrary SciLexer.dll failure..."), _T("Error"), MB_ICONSTOP | MB_OK );
		return FALSE;
	}
#endif

	HRESULT hRes = ::CoInitialize(NULL);
// If you are running on NT 4.0 or higher you can use the following call instead to 
// make the EXE free threaded. This means that calls come in on a random RPC thread.
//	HRESULT hRes = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
	ATLASSERT(SUCCEEDED(hRes));

	// this resolves ATL window thunking problem when Microsoft Layer for Unicode (MSLU) is used
	::DefWindowProc(NULL, 0, 0, 0L);

	AtlInitCommonControls(ICC_COOL_CLASSES | ICC_BAR_CLASSES);	// add flags to support other controls

	hRes = _Module.Init(NULL, hInstance);
	ATLASSERT(SUCCEEDED(hRes));

	int nRet = Run(lpstrCmdLine, nCmdShow);

	_Module.Term();
	::CoUninitialize();

#ifdef STATIC_BUILD_SCI
	Scintilla_ReleaseResources();
#else
	if( m_hSciLexerDll != NULL )
	{
		::FreeLibrary( m_hSciLexerDll );
	}
#endif

	return nRet;
}

4. 在 WtlScintillaSDIView.h 增加一 Scintilla 封装类,继承自CWindowImpl,如 CScintillaWnd

#include "Scintilla.h"
#include "SciLexer.h"

class CScintillaWnd : public CWindowImpl<CScintillaWnd>
{
public:
	DECLARE_WND_CLASS(NULL)

	CScintillaWnd()
	{
	}

	BEGIN_MSG_MAP(CScintillaWnd)
	END_MSG_MAP()


	HWND Create( HWND hWndParent, const ATL::_U_RECT& rect, DWORD dwExStyle = 0 )
	{
		// TODO: 在此添加专用代码和/或调用基类
		return CWindow::Create( _T("Scintilla"), hWndParent, rect, _T(""), WS_CHILD | WS_VISIBLE, dwExStyle );
	}


	/////////////////////////////////////
	// @mfunc init the view with reasonable defaults
	// @rvalue void | not used
	//
	void Init()
	{
		// clear all text styles
		SendMessage(SCI_CLEARDOCUMENTSTYLE, 0, 0);
		// set the number of styling bits to 7 - the asp/html views need a lot of styling - default is 5
		// If you leave the default you will see twiggle lines instead of ASP code
		SendMessage(SCI_SETSTYLEBITS, 7, 0);
		// set the display for indetation guides to on - this displays virtical dotted lines from the beginning of
		// a code block to the end of the block
		SendMessage(SCI_SETINDENTATIONGUIDES, TRUE, 0);
		// set tabwidth to 4
		SendMessage(SCI_SETTABWIDTH,4,0);
		// set indention to 4
		SendMessage(SCI_SETINDENT,4,0);
		// set the caret blinking time to 400 milliseconds
		SendMessage(SCI_SETCARETPERIOD,400,0);
		// display fold margins
		SetFold();
		// hide SelectionMargin
		SendMessage( SCI_SETMARGINWIDTHN, 1, 0 );
		// set markersymbol for marker type 0 - bookmark
		SendMessage(SCI_MARKERDEFINE, 0, SC_MARK_CIRCLE);
		// set the forground color for some styles
		SendMessage(SCI_STYLESETFORE, 0, RGB(0,0,0));
		SendMessage(SCI_STYLESETFORE, 2, RGB(0,64,0));
		SendMessage(SCI_STYLESETFORE, 5, RGB(0,0,255));
		SendMessage(SCI_STYLESETFORE, 6, RGB(200,20,0));
		SendMessage(SCI_STYLESETFORE, 9, RGB(0,0,255));
		SendMessage(SCI_STYLESETFORE, 10, RGB(255,0,64));
		SendMessage(SCI_STYLESETFORE, 11, RGB(0,0,0));
		// set the backgroundcolor of brace highlights
		SendMessage(SCI_STYLESETBACK, STYLE_BRACELIGHT, RGB(0,255,0));
		// set end of line mode to CRLF
		SendMessage(SCI_CONVERTEOLS, 2, 0);
		SendMessage(SCI_SETEOLMODE, 2, 0);
		//   SendMessage(SCI_SETVIEWEOL, TRUE, 0);

		//显示当前行的淡黄色背景
		SendMessage(SCI_SETCARETLINEVISIBLE,TRUE,0);
		SendMessage(SCI_SETCARETLINEBACK, RGB(255,255,0),0);
		SendMessage(SCI_SETCARETLINEBACKALPHA,100,0);
	}

	void InitScintillaEdit(int nSize,const TCHAR* face)
	{
		Init();
		SetDefaultColorFont(nSize,face);
		UpdateLineNumberWidth();
	}

	void SetDefaultColorFont(int nSize,const TCHAR* face)
	{
		SendMessage(SCI_SETSELFORE,TRUE,RGB(255,255,255));
		//选中行的颜色
		SendMessage(SCI_SETSELBACK,TRUE,RGB(10,36,106));

		//默认文本颜色
		SendMessage(SCI_STYLESETFORE, STYLE_DEFAULT, RGB(0x00,0x00,0x00));
		SendMessage(SCI_STYLESETBACK, STYLE_DEFAULT, RGB(0xff,0xff,0xff));
		SendMessage(SCI_STYLESETSIZE, STYLE_DEFAULT, nSize);
		SendMessage(SCI_STYLESETFONT, STYLE_DEFAULT, reinterpret_cast<LPARAM>(face));
	}

	//自动Fold
	void SetFold( BOOL bFold = TRUE )
	{
		if( bFold )
		{
			// source folding section
			// tell the lexer that we want folding information - the lexer supplies "folding levels"
			SendMessage(SCI_SETPROPERTY, (WPARAM) "fold", (LPARAM) "1" );
			SendMessage(SCI_SETPROPERTY, (WPARAM) "fold.comment", (LPARAM) "1" );
			SendMessage(SCI_SETPROPERTY, (WPARAM) "fold.at.else", (LPARAM) "1" );
			SendMessage(SCI_SETPROPERTY, (WPARAM) "fold.preprocessor", (LPARAM) "1" );
			SendMessage(SCI_SETPROPERTY, (WPARAM) "styling.within.preprocessor", (LPARAM) "1" );

			SendMessage(SCI_SETMARGINTYPEN, 2, SC_MARGIN_SYMBOL);//页边类型
			SendMessage(SCI_SETMARGINMASKN, 2, SC_MASK_FOLDERS); //页边掩码
			SetMarginWidthN(2, 16); //SendMessage(SCI_SETMARGINWIDTHN, 2, 16); //页边宽度
			SendMessage(SCI_SETMARGINSENSITIVEN, 2, TRUE); //响应鼠标消息

			// 折叠标签样式
			SendMessage(SCI_MARKERDEFINE, SC_MARKNUM_FOLDER, SC_MARK_CIRCLEPLUS);
			SendMessage(SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPEN, SC_MARK_CIRCLEMINUS);
			SendMessage(SCI_MARKERDEFINE, SC_MARKNUM_FOLDEREND,  SC_MARK_CIRCLEPLUSCONNECTED);
			SendMessage(SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPENMID, SC_MARK_CIRCLEMINUSCONNECTED);
			SendMessage(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNERCURVE);

			SendMessage(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE);
			SendMessage(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNERCURVE);

			// 折叠标签线颜色
			SendMessage(SCI_MARKERSETBACK, SC_MARKNUM_FOLDERSUB, 0xff0000); //蓝色
			SendMessage(SCI_MARKERSETBACK, SC_MARKNUM_FOLDERMIDTAIL, 0xff0000);
			SendMessage(SCI_MARKERSETBACK, SC_MARKNUM_FOLDERTAIL, 0xff0000);

			SendMessage(SCI_SETFOLDFLAGS, 16, 0); //如果折叠就在折叠行的下各画一条横线
		}
		else
		{
			SetMarginWidthN(2, 0); //SendMessage( SCI_SETMARGINWIDTHN, 2, 0 ); // FoldMargin
		}
	}

	void ToggleFold(long line)
	{
		SendMessage(SCI_TOGGLEFOLD, static_cast<WPARAM>(line), 0);
	}

	int GetMarginWidthN(int margin)
	{
		return SendMessage(SCI_GETMARGINWIDTHN, static_cast<WPARAM>(margin), 0);
	}

	void SetMarginWidthN(int margin, int mask)
	{
		SendMessage(SCI_SETMARGINWIDTHN, static_cast<WPARAM>(margin), static_cast<LPARAM>(mask));
	}

	void UpdateLineNumberWidth(void)
	{
		//start 显示行号
		long  iLineMarginWidthNow;
		long  iLineMarginWidthFit;
		long iLineNum = SendMessage( SCI_GETLINECOUNT, 0, 0 );
		long iLineNumCount = 1;
		while( iLineNum != 0 )
		{
			++iLineNumCount;
			iLineNum /= 10;
		}
		iLineMarginWidthNow = SendMessage( SCI_GETMARGINWIDTHN, 0, 0 );
		long charWidth = SendMessage( SCI_TEXTWIDTH, STYLE_LINENUMBER, (LPARAM)("9") );
		iLineMarginWidthFit = charWidth * iLineNumCount;
		if ( iLineMarginWidthNow != iLineMarginWidthFit )
		{
			SendMessage( SCI_SETMARGINWIDTHN, 0, iLineMarginWidthFit );
		}
		//end of 显示行号
	}

	long LineFromPosition(long pos)
	{
		return SendMessage(SCI_LINEFROMPOSITION, static_cast<WPARAM>(pos), 0);
	}
};
5. 在 CWtlScintillaSDIView 创建 CScintillaWnd 并处理简单消息
class CWtlScintillaSDIView : public CWindowImpl<CWtlScintillaSDIView>
{
public:
	DECLARE_WND_CLASS(NULL)

	CScintillaWnd * m_pScintillaCtrl;

	~CWtlScintillaSDIView()
	{
		if( NULL != m_pScintillaCtrl )
		{
			delete m_pScintillaCtrl;
		}
	}

	BOOL PreTranslateMessage(MSG* pMsg)
	{
		pMsg;
		return FALSE;
	}

	BEGIN_MSG_MAP(CWtlScintillaSDIView)
		MESSAGE_HANDLER(WM_NOTIFY, OnNotify)
		MESSAGE_HANDLER(WM_SIZE, OnSize)
		MESSAGE_HANDLER(WM_CREATE, OnCreate)
		MESSAGE_HANDLER(WM_PAINT, OnPaint)
	END_MSG_MAP()

// Handler prototypes (uncomment arguments if needed):
//	LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
//	LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
//	LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)

	LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
	{
		CPaintDC dc(m_hWnd);

		//TODO: Add your drawing code here

		return 0;
	}

	LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		RECT rcWin;
		GetClientRect( &rcWin );
		m_pScintillaCtrl = new CScintillaWnd();
		m_pScintillaCtrl->Create( m_hWnd, rcWin, 0 ); // cancel WS_EX_CLIENTEDGE ( 3D )
		m_pScintillaCtrl->InitScintillaEdit( 12, _T("Courier New") );
		m_pScintillaCtrl->ShowWindow( SW_SHOW );

		return 0;
	}

	LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		RECT rcWin;
		GetClientRect( &rcWin );
		m_pScintillaCtrl->MoveWindow( &rcWin );

		return 0;
	}

	LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		struct SCNotification* scn = (struct SCNotification*)lParam;
		LPNMHDR pnmh = (LPNMHDR)lParam;
		switch(pnmh->code)
		{
			case SCN_MODIFIED://修改了文件
			case SCN_ZOOM://放大,缩小
				if( m_pScintillaCtrl->GetMarginWidthN(0) != 0 )
					m_pScintillaCtrl->UpdateLineNumberWidth();
				break;
			case SCN_MARGINCLICK://确定是Fold页边点击事件
				{
					long n = m_pScintillaCtrl->LineFromPosition( scn->position );
					m_pScintillaCtrl->ToggleFold( n );
				}
				break;
			case SCN_UPDATEUI://界面更新(单击鼠标,按下箭头等)
				break;
		}

		return 0;
	}
};
现在就可以编译运行,添加 Include 路径 scintilla\include

A 需要将事先编译好的 SciLexer.dll放到项目目录下。

B 静态链接 ScintillaLib.lib 使用 /MT编译

( 参考Scintilla 3.2.5在VC中的编译(动态、静态)

静态 链接需在工程属性,Linker→Input→Additional Dependencies填入 ScintillaLib.lib IMM32.lib

并添加C预处理程序定义 STATIC_BUILD_SCI


6.   CScintillaWnd 添加 C++ 语法高亮

//  
const char cppKeyWords[] =  
"and and_eq asm auto bitand bitor bool break "  
"case catch char class compl const const_cast continue "  
"default delete do double dynamic_cast else enum explicit export extern false float for "  
"friend goto if inline int long mutable namespace new not not_eq "  
"operator or or_eq private protected public "  
"register reinterpret_cast return short signed sizeof static static_cast struct switch "  
"template this throw true try typedef typeid typename union unsigned using "  
"virtual void volatile wchar_t while xor xor_eq ";  
    void SetCppSyntax()  
    {  
        SendMessage( SCI_SETLEXER, SCLEX_CPP );  
        SendMessage(SCI_SETKEYWORDS, 0, (LPARAM)cppKeyWords );  
        // 下面设置各种语法元素前景色  
        SendMessage(SCI_STYLESETFORE, SCE_C_WORD, 0x00FF0000);   //关键字  
        SendMessage(SCI_STYLESETFORE, SCE_C_STRING, 0x001515A3); //字符串  
        SendMessage(SCI_STYLESETFORE, SCE_C_CHARACTER, 0x001515A3); //字符  
        SendMessage(SCI_STYLESETFORE, SCE_C_PREPROCESSOR, 0x00808080);//预编译开关  
        SendMessage(SCI_STYLESETFORE, SCE_C_COMMENT, 0x00008000);//块注释  
        SendMessage(SCI_STYLESETFORE, SCE_C_COMMENTLINE, 0x00008000);//行注释  
        SendMessage(SCI_STYLESETFORE, SCE_C_COMMENTDOC, 0x00008000);//文档注释(/**开头)  
        SendMessage(SCI_STYLESETFORE, SCE_C_NUMBER, 0x000010ff);//数字  
        SendMessage(SCI_STYLESETFORE, SCE_C_OPERATOR, 0x0000c0f0);//操作  
    }
修改

	void InitScintillaEdit(int nSize,const TCHAR* face)
	{
		SetCppSyntax();
		Init();
		SetDefaultColorFont(nSize,face);
		UpdateLineNumberWidth();
	}
现在输入的C++代码就会有语法高亮,并有Fold


6, 增加OpenFile()

下面演示一简易版

BOOL OpenFile(LPCTSTR lpFileName)
{
	HANDLE m_hFile = INVALID_HANDLE_VALUE;
	// map modeNoInherit flag
	SECURITY_ATTRIBUTES sa;
	sa.nLength = sizeof(sa);
	sa.lpSecurityDescriptor = NULL;
	sa.bInheritHandle = 0; //modeNoInherit
	m_hFile = ::CreateFile( lpFileName, GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, &sa, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL );
	ULONG nFileLength = static_cast<ULONG>( ::GetFileSize( m_hFile, NULL ) );

	char *pBuffer;
	pBuffer=new char[nFileLength+1];

	BOOL bRet = ::ReadFile( m_hFile, pBuffer, nFileLength, &nFileLength, NULL );

	::CloseHandle( m_hFile );

	if (SendMessage(SCI_GETREADONLY,0,0))
	{
		SendMessage(SCI_SETREADONLY,FALSE,0);
	}

	SendMessage(SCI_CANCEL,0,0);
	SendMessage(SCI_SETUNDOCOLLECTION,0,0);
	SendMessage(SCI_EMPTYUNDOBUFFER,0,0);

	//如果文本没有只读属性,则清除所有文字。
	SendMessage(SCI_CLEARALL,0,0);

	//从所有行中删除标记,若markerNumber=-1,则删除所有标记。
	SendMessage(SCI_MARKERDELETEALL,(WPARAM)-1,0);

	SendMessage(SCI_ADDTEXT,nFileLength,(LPARAM)pBuffer); //SetText

	SendMessage(SCI_SETUNDOCOLLECTION,1,0);
	SendMessage(EM_EMPTYUNDOBUFFER,0,0);
	SendMessage(SCI_SETSAVEPOINT,0,0);
	SendMessage(SCI_GOTOPOS,0,0);
	SendMessage(SCI_CHOOSECARETX,0,0);

	UpdateLineNumberWidth();

	delete [] pBuffer;

	return TRUE;
}


VC2005 演示代码 WtlScintillaSDI-vc2005.7z http://pan.baidu.com/share/link?shareid=386165&uk=201934825

http://blog.csdn.net/gocad/article/details/8826303


参考资料:
1.Scintilla Documentation  http://www.scintilla.org/ScintillaDoc.html

2.Scintilla 在MFC中的简易使用(动态、静态)

3.Scintilla的高级技法 http://yp.oss.org.cn/software/show_resource.php?resource_id=854


补充资料,以下为 Gilad Novik 提供的 AtlScintilla.h an easy wrapper for the Scintilla control, to be used with ATL/WTL projects.

Date: 12/15/2005 http://sourceforge.net/p/scintilla/feature-requests/283/

Date: 06/01/2006 http://code.google.com/p/winx/source/browse/tags/scintilla-1.77/wtl?r=1519

SendMessage(SCI_USEPOPUP,0,0); //可关闭Scintilla 右键菜单
visualfc 一个不错的 WTL 开发辅助工具,提供方便的 Windows消息,菜单/控件消息/通知,DDX/DDV,UpdateUI 增删函数映射功能。

 大家可从 http://code.google.com/p/visualfc/ 下载, 从 visualfc bolg :http://blog.csdn.net/visualfc/ 得到帮助

下面为 在Code::Blocks 12.11 中使用的截图

更新 VisualFC 0.82 使其正确列举出所有菜单项 ID

猜你喜欢

转载自blog.csdn.net/gocad/article/details/8826303