Scintilla 在MFC中的簡易使用(動態、靜態)

Scintilla 在MFC中的簡易使用(動態、靜態)

 Scintilla是一個開源的源代碼編輯組件。在這裏記錄下它在MFC中的簡易使用。

Scintilla 3.24在MFC中的使用(動態、靜態) 一文使用的別人封裝過的類。至於怎樣去封裝,沒有詳細說明。

下面將簡單介紹在MFCSDI框架下如何封裝Scintilla,提供一個玩具級的演示示例。本文使用的是Scintilla 3.2.5

1.      新建一MFC SDI 項目,如:SdiScintillaMFC


2.      (動態、靜態) 使用 Scintilla 代碼初始化。

在 SdiScintillaMFC 中添加如下代碼:

HMODULE m_hSciLexerDll;
#ifdef STATIC_BUILD_SCI
#include "Scintilla.h"
#endif
BOOL CSdiScintillaMFCApp::InitInstance()
{
#ifdef STATIC_BUILD_SCI
	Scintilla_RegisterClasses(AfxGetInstanceHandle());
#else
	m_hSciLexerDll = NULL;
	m_hSciLexerDll = LoadLibrary(_T("SciLexer.dll"));
	if (NULL == m_hSciLexerDll)
	{
		AfxMessageBox(_T("LoadLibrary SciLexer.dll failure..."));
		return FALSE;
	}
#endif
…
}

int CSdiScintillaMFCAp::ExitInstance() 
{
	// TODO: Add your specialized code here and/or call the base class
#ifdef STATIC_BUILD_SCI
	Scintilla_ReleaseResources();
#else
	if (m_hSciLexerDll != NULL)
	{	
		::FreeLibrary(m_hSciLexerDll);
	}
#endif
	
	return CWinApp::ExitInstance();
}
3.      增加一Scintilla封裝類,繼承自CWnd,如ScintillaCtrl

增加如下函數

BOOL ScintillaCtrl::Create(DWORD dwExStyle,const RECT& rect, CWnd* pParentWnd)
{
	// TODO: 在此添加專用代碼和/或調用基類
	BOOL bRet;
	bRet= CWnd::CreateEx(dwExStyle,_T("Scintilla"), _T(""),
		WS_CHILD | WS_VISIBLE, rect,pParentWnd, IDC_STATIC);

	return bRet;
}

/////////////////////////////////////
// @mfunc init the view with reasonable defaults
// @rvalue void | not used
//
void ScintillaCtrl::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_SETCARETLINEVISIBLE,TRUE,0);
	SendMessage(SCI_SETCARETLINEBACK, RGB(255,255,0),0);
	SendMessage(SCI_SETCARETLINEBACKALPHA,100,0);
}


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

void ScintillaCtrl::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 ScintillaCtrl::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); // FoldMargin頁邊寬度
		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 ScintillaCtrl::ToggleFold(long line)
{
	SendMessage(SCI_TOGGLEFOLD, static_cast<WPARAM>(line), 0);
}

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

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

void ScintillaCtrl::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 ScintillaCtrl::LineFromPosition(long pos)
{
	return SendMessage(SCI_LINEFROMPOSITION, static_cast<WPARAM>(pos), 0);
}

4.      在 CSdiScintillaMFCView 創建 ScintillaCtrl 並處理簡單消息

ScintillaCtrl* m_pScintillaCtrl;
CSdiScintillaMFCView::~CScintillaMFCView()
{
	if( NULL != m_pScintillaCtrl )
	{
		delete m_pScintillaCtrl;
	}
}
/////////////////////////////////////////////////////////////////////////////
// CSdiScintillaMFCView message handlers

int CSdiScintillaMFCView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CView::OnCreate(lpCreateStruct) == -1)
		return -1;

	// TODO: Add your specialized creation code here
	CRect rcWin;
	GetClientRect(&rcWin);
	m_pScintillaCtrl = new ScintillaCtrl();
	m_pScintillaCtrl->Create(WS_EX_CLIENTEDGE, rcWin, this ); 
	m_pScintillaCtrl->InitScintillaEdit(12,_T("Courier New"));
	m_pScintillaCtrl->ShowWindow(SW_SHOW);

	return 0;
}

void CSdiScintillaMFCView::OnSize(UINT nType, int cx, int cy)
{
	CView::OnSize(nType, cx, cy);

	// TODO: Add your message handler code here
	CRect rcWin;
	GetClientRect(&rcWin);
	m_pScintillaCtrl->MoveWindow(&rcWin);
}

BOOL CSdiScintillaMFCView::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
	// TODO: Add your specialized code here and/or call the base class
	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 CView::OnNotify(wParam, lParam, pResult);
}

 現在就可以編譯運行,添加 Include 路徑 scintilla\include

A 動態編譯需要將事先編譯好的 SciLexer.dll放到項目目錄下。

B 全靜態編譯,設置Use MFC in a Static Library 且ScintillaLib.lib使用 /MT編譯

( 參考Scintilla 3.2.5在VC中的編譯(動態、靜態)

或者 動態編譯使用 Use MFC in a Share DLL, 則ScintillaLib.lib使用 /MD編譯

靜態編譯需在工程屬性,Linker→Input→Additional Dependencies填入ScintillaLib.lib IMM32.lib

並添加C預處理程序定義 STATIC_BUILD_SCI


5.    添加 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 ScintillaCtrl::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 ScintillaCtrl::InitScintillaEdit(int nSize,const TCHAR* face)
{
	SetCppSyntax();// 增加
	Init();
	SetDefaultColorFont(nSize,face);
	UpdateLineNumberWidth();
}

現在輸入的C++代碼就會有語法高亮,並有Fold

.

6, 增加OpenFile()

下面演示一簡易版

BOOL ScintillaCtrl::OpenFile(CString lpFileName)
{
	CStdioFile stdFile( lpFileName, CFile::modeRead | CFile::typeBinary );
	ULONG nFileLength=static_cast<ULONG>(stdFile.GetLength());

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

	nFileLength=stdFile.Read(pBuffer,nFileLength);

	stdFile.Close();

	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;
}

VC6.0 演示代碼 SdiScintillaMFC http://download.csdn.net/detail/gocad/5268577

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

參考資料:
1.Scintilla Documentation  http://www.scintilla.org/ScintillaDoc.html
2.MFC classes to encapsulate the Scintilla edit control  http://www.naughter.com/scintilla.html
3.語法高亮編輯控件Scintilla在MFC中的簡單使用 http://www.qingfengju.com/article.asp?id=14
4.用Scintilla讓程序支持語法高亮並且編譯 http://hi.baidu.com/kxw102/item/b7e701a569d685de5af19138
5.Scintilla開源庫使用指南  http://www.cnblogs.com/superanyi/archive/2011/04/07/2008632.h.

6. Scintilla3.24在MFC中的使用(動態、靜態)  http://blog.csdn.net/akof1314/article/details/8585917

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章