Scintilla是一个免费的、跨平台、支持语法高亮的编辑控件。它完整支持源代码的编辑和调试,包括语法高亮、错误指示、代码自动完成 (code completion)和调用提示(call tips)。它包含页边(margin)和标记(marker)功能,可用于显示行号、标记断点、折叠和高亮当前行。
VC++中快速开发,可下载CScintillaCtrl控件(下载地址:http://www.naughter.com/download/scintillawrappers.zip)。CScintillaCtrl将Scintilla原生态接口进行封装成类,调用更方便、开发更快速有效。
为了简单方便,给CScintillaCtrl里面新增加了2个创建函数
// 第1种先只管创建控件,再设置控件显示位置
BOOL CScintillaCtrl::CreateMe(HWND hParentWnd)
{
if (::IsWindow(GetSafeHwnd()))
{
::SetParent(GetSafeHwnd(), hParentWnd);
return TRUE; //已经创建了就不再创建了
}
const CRect rcWindow;
return Create(WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER, rcWindow,
CWnd::FromHandle(hParentWnd), 0);
}
// 第2种根据界面上一个现有的控件(比如CStatic,借用CStatic的控件ID来创建控件)
BOOL CScintillaCtrl::CreateFromWnd(UINT nID, CWnd* pParent)
{
CWnd wnd;
if (!wnd.SubclassDlgItem(nID, pParent))
return FALSE;
CRect rcWindow;
wnd.GetWindowRect(&rcWindow);
pParent->ScreenToClient(&rcWindow);
wnd.DestroyWindow();
return Create(WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER, rcWindow, pParent, nID);
}
1、控件声明和初始化
std::unique_ptr<CScintillaCtrl> m_pEdit;
m_pEdit = std::make_unique<CScintillaCtrl>();
或
CScintillaCtrl* m_pEdit;
m_pEdit = new CScintillaCtrl();
初始完成以后,千万给忘记调用Create函数来创建控件。
2、有关Scintilla控件的调用,在网上流传甚多,这里只介绍重点
1)如何给页边距设置背景色和设定字体颜色
// 页边编号从左往右,依次编号是0、1、2、3、4,可以显示数字和符号
// 为了方便理解,将值给定参数名对应起来
int margin = 0; // 页边编号
int width = 16; // 页边宽度(如果不设定宽度,默认值将为16)
BOOL allow_click = TRUE;// 是否允许页边触发鼠标单击事件
// 设置编号为0的页边显示行号
m_pEdit->SetMarginTypeN(margin, SC_MARGIN_NUMBER);
//设置页边宽度,默认宽度为0,即不显示行号
m_pEdit->SetMarginWidthN(margin, width);
//设置页边是否接受鼠标点击事件
m_pEdit->SetMarginSensitiveN(margin, allow_click);
// 设置页边显示的文本颜色-红色(注意颜色值顺序是BGR,而不是RGB,要不然颜色就反了)
m_pEdit->StyleSetFore(STYLE_LINENUMBER, 0x000000FF);
// 设置页边背景色-绿色
m_pEdit->StyleSetBack(STYLE_LINENUMBER, 0x0000FF00);
2)如何扩展关键字列表,并且给关键字设定颜色
如果我们需要扩展自己的词法解析器,就需要根据自己的语法类型进行扩展,这里我以Pascal词法解析器为例,原生态的Pascal只支持一种关键词类型,如何新增一种关键词类型呢?首先我们要添加关键词列表
// Pascal语法解析器
m_pEdit->SetLexer(SCLEX_PASCAL);
// 设置关键词列表1
m_pEdit->SetKeyWords(0, szKeyWordList1);
// 给关键词列表1中的字符串指定一个红色
m_pEdit->StyleSetFore(SCE_PAS_WORD, clrRed);
//设置关键词列表2
m_pEdit->SetKeyWords(1, szKeyWordList2);
// 给关键词列表1中的字符串指定一个蓝色
m_pEdit->StyleSetFore(SCE_PAS_WORD2, clrBlue);
SCE_PAS_WORD2是我们新增加一个关键吃类型,打开SciLexer.h,增加宏定义
#define SCE_PAS_DEFAULT 0
#define SCE_PAS_IDENTIFIER 1
#define SCE_PAS_COMMENT 2
#define SCE_PAS_COMMENT2 3
#define SCE_PAS_COMMENTLINE 4
#define SCE_PAS_PREPROCESSOR 5
#define SCE_PAS_PREPROCESSOR2 6
#define SCE_PAS_NUMBER 7
#define SCE_PAS_HEXNUMBER 8
#define SCE_PAS_WORD 9
#define SCE_PAS_STRING 10
#define SCE_PAS_STRINGEOL 11
#define SCE_PAS_CHARACTER 12
#define SCE_PAS_OPERATOR 13
#define SCE_PAS_ASM 14
#define SCE_PAS_WORD2 15 // 其中这里是新增加的一个类型
有了SCE_PAS_WORD2定义,打开LexPascal.cxx,在这里对关键词类型进行判断,指定状态值就行了
static void ClassifyPascalWord(WordList *keywordlists[], StyleContext &sc, int &curLineState, bool bSmartHighlighting) {
WordList& keywords = *keywordlists[0];
WordList& keywords2 = *keywordlists[1];
// TODO. 所有对SCE_PAS_WORD值的判断的地方,添加对值SCE_PAS_WORD2的判断即可。
......
}
效果图: