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.youkuaiyun.com/gocad/article/details/8826303
1.Scintilla Documentation http://www.scintilla.org/ScintillaDoc.html
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.youkuaiyun.com/visualfc/ 得到帮助
下面为 在Code::Blocks 12.11 中使用的截图