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\includeA 需要將事先編譯好的 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
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 中使用的截圖