Scintilla介绍
挺好的代码编辑开发组件,与其他代码编辑软件一样有关键字高亮,函数注释,行号,调试标记,自动缩进,代码折叠,等功能.它的词法分析支持很多语言,比如:Phthon,C++,HTML,XML,PERL,SQL,VB,makefile,VHDL,等等多大几十种.对于小语种特别好,因为它可以让你定义关键字,也就是说你自己发明的语言,它也可以很好的支持.
你需要要有一定的MFC的基础,才能理解后面的内容.
如何控制Scintilla编辑控件
您可以通过向编辑控件发送命令来控制 Scintilla。 有两种方法可以做到这一点。一种简单快捷的方法。
控制Scintilla的简单方法
简单的方法就像任何其他窗口控件一样。您可以将消息发送到 Scintilla编辑控件并从控件接收通知。(请注意,通知 被发送到 Scintilla 编辑控件的父窗口。
Scintilla 编辑控件知道每个命令的特殊消息。 要将命令发送到 Scintilla 编辑控件,您可以使用 SendMessage 函数。
SendMessage(hwndScintilla,sci_command,wparam,lparam);
某些命令将返回一个值,未使用的参数应设置为 NULL。
控制Scintilla的快速方法
控制 Scintilla 编辑控件的快速方法是自行调用消息处理函数。 您可以检索指向 Scintilla 编辑控件的消息处理函数的指针,并且 直接调用它以执行命令。这种方式比 SendMessage() 方式快得多。
首先,您必须使用 SCI_GETDIRECTFUNCTION 和 SCI_GETDIRECTPOINTER 命令 检索指向函数的指针和一个指针,该指针在调用检索到时必须是第一个参数 函数指针。 您必须使用发送消息方式执行此操作:)
整个事情必须看起来像这样:
int (*fn)(void*,int,int,int);
void * ptr;
int canundo;
fn = (int (__cdecl *)(void *,int,int,int))SendMessage(
hwndScintilla,SCI_GETDIRECTFUNCTION,0,0);
ptr = (void *)SendMessage(hwndScintilla,SCI_GETDIRECTPOINTER,0,0);
canundo = fn(ptr,SCI_CANUNDO,0,0);
以“fn”作为指向 Scintilla 控件的消息处理函数的函数指针 和“ptr”作为必须用作第一个参数的指针。 接下来的参数是 Scintilla 命令及其两个(可选)参数。
我将如何收到通知?
每当发生 Scintilla 想要通知您某事的事件时,Scintilla 编辑控件 将通知发送到父窗口。这是通过WM_NOTITY消息完成的。 收到该消息时,您必须在 xxx 结构中查找实际消息。
因此,在 Scintillas 父窗口消息处理函数中,您必须包含如下代码:
NMHDR *lpnmhdr;
[...]
case WM_NOTIFY:
lpnmhdr = (LPNMHDR) lParam;
if(lpnmhdr->hwndFrom==hwndScintilla)
{
switch(lpnmhdr->code)
{
case SCN_CHARADDED:
/* Hey, Scintilla just told me that a new */
/* character was added to the Edit Control.*/
/* Now i do something cool with that char. */
break;
}
}
break;
如何连接MFC
需要哪些文件
Scintilla.h,SciLexer.h,SciLexer.dll三个文件.
加载动态库
#include "SciLexer.h"
#include "Scintilla.h"
HMODULE hmod = LoadLibrary("SciLexer.DLL");
if (hmod==NULL)
{
MessageBox(hwndParent,
"The Scintilla DLL could not be loaded.",
"Error loading Scintilla",
MB_OK | MB_ICONERROR);
}
新建CScintillaWnd类
是CWnd的子类,需要如下成员变量
SciFnDirect pSciMsg;
sptr_t pSciWndData ;
sptr_t SendDirect(unsigned int iMessage, uptr_t wParam = 0, sptr_t lParam = 0)//与Scintilla通讯的函数,后面会大量使用
{
return m_fnDirect(m_ptrDirect, iMessage, wParam, lParam);
}
重写CWnd的如下函数:
virtual BOOL PreTranslateMessage(MSG* pMsg);//响应热键
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);//响应create事件消息
afx_msg void OnContextMenu(CWnd* /*pWnd*/, CPoint /*point*/);//响应右键菜单消息
virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult);//响应其他消息
m_fnDirect,m_ptrDirect两个变量是Scintilla回调函数及窗体指针,这是与Scintilla组件通讯函数,
m_fnDirect():Scintilla的消息函数,m_ptrDirect:指针标识正在使用哪个 Scintilla 窗口,只需要赋值一次,
在函数OnCreate()中确定回调函数的指针.,如下函数
int CScintillaWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
HWND hwndEditor = this->GetSafeHwnd();
pSciMsg = (SciFnDirect)::SendMessage(hwndEditor, SCI_GETDIRECTFUNCTION, 0, 0);//返回Scintilla的消息函数指针
pSciWndData = (sptr_t)::SendMessage(hwndEditor, SCI_GETDIRECTPOINTER, 0, 0);//返回Scintilla窗口指针
}
到此,SendDirect()就可以正常工作了.
新建一个dialog
增加一个成员变量,并重写几个函数,如下类说明:
CScintillaWnd mScintillaWnd;
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult);
在OnCreate()函数中加如下,一旦dialog创建,mScintillaWnd窗口就启动.
if (!mScintillaWnd.Create(_T("Title"), WS_CHILD | WS_VISIBLE, CRect(0, 0, 0, 0), this, 10000))
{
return -1;
}
在OnNotify中增加如下语句,dialog消息就会传递到给mScintillaWnd对象
mScintillaWnd.SendMessage(WM_NOTIFY, wParam, lParam);
到此,MFC窗体已经与Scintilla连接了,下面就要设置Scintilla,加载文档等功能
如何配置Scintilla
在int CScintillaWnd::OnCreate()函数中增加配置代码如下:
// 支持中文
SendDirect(SCI_SETCODEPAGE, SC_CP_UTF8);//SCI_SETCODEPAGE:设置代码编码方式 SC_CP_UTF8 为单字节UTF-8
//设置语法高亮
//关键字
const char* g_szKeywords =
"asm auto bool break case catch char class const "
"const_cast continue default delete do double "
"dynamic_cast else enum explicit extern false finally "
"float for friend goto if inline int long mutable "
"namespace new operator private protected public "
"register reinterpret_cast register 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";
SendDirect(SCI_SETLEXER, SCLEX_CPP); // C++语法解析或词法分析
SendDirect(SCI_SETKEYWORDS, 0, (sptr_t)g_szKeywords); // 设置关键字
//0是行号 2是折叠 1是跟踪行号
SendDirect(SCI_SETMARGINTYPEN, 1, SC_MARGIN_SYMBOL);
SendDirect(SCI_SETMARGINWIDTHN, 1, 9);
SendDirect(SCI_MARKERSETFORE, 1, 0x0000ff); //0-红色
SendDirect(SCI_STYLESETFORE, SCE_C_PREPROCESSOR, 0x00808080); // 预编译开关
SendDirect(SCI_STYLESETFORE, SCE_C_COMMENTDOC, 0x00008000); // 文档注释(/**开头)
SendDirect(SCI_STYLESETFORE, SCE_C_COMMENT, 0x00008000); // 块注释
SendDirect(SCI_STYLESETFORE, SCE_C_COMMENTLINE, 0x00008000); // 行注释
SendDirect(SCI_STYLESETFORE, SCE_C_NUMBER, RGB(0, 0, 255)); // 数字
SendDirect(SCI_STYLESETFORE, SCE_C_IDENTIFIER, RGB(0, 0, 255)); // 标识符
SendDirect(SCI_STYLESETFORE, SCE_C_WORD, RGB(163, 21, 21)); // 关键字
SendDirect(SCI_SETCARETLINEVISIBLE, TRUE); // 设置当前行高亮
// TAB宽度
SendDirect(SCI_SETTABWIDTH, 4);
//默认字体
SetDefaultFont(12, _T("新宋体"));
//行号颜色
SendDirect(SCI_STYLESETFORE, STYLE_LINENUMBER, RGB(43, 145, 175));
SendDirect(SCI_SETMOUSEDWELLTIME, 1000);
SendDirect(SCI_SETSELBACK, true, RGB(51, 153, 255));//选择文本背景色
实现函数提示功能
你首先需要了解Scintilla的消息格式
struct Sci_NotifyHeader { // This matches the Win32 NMHDR structure
void *hwndFrom; // 窗口指针
uptr_t idFrom; // CtrlID of the window issuing the notification
unsigned int code; // The SCN_* notification code
};
struct SCNotification {
struct Sci_NotifyHeader nmhdr;
Sci_Position position;//以下块备注是指哪些消息,这个值是有效,SCN_*是Scintilla发出的消息编号
/* SCN_STYLENEEDED, SCN_DOUBLECLICK, SCN_MODIFIED, SCN_MARGINCLICK, */
/* SCN_MARGINRIGHTCLICK, SCN_NEEDSHOWN, SCN_DWELLSTART, SCN_DWELLEND, */
/* SCN_CALLTIPCLICK, SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, */
/* SCN_HOTSPOTRELEASECLICK, SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
/* SCN_USERLISTSELECTION, SCN_AUTOCSELECTION, SCN_AUTOCSELECTIONCHANGE */
int ch;
/* SCN_CHARADDED, SCN_KEY, SCN_AUTOCCOMPLETE, SCN_AUTOCSELECTION, */
/* SCN_USERLISTSELECTION */
int modifiers;
/* SCN_KEY, SCN_DOUBLECLICK, SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, */
/* SCN_HOTSPOTRELEASECLICK, SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
int modificationType; /* SCN_MODIFIED */
const char *text;
/* SCN_MODIFIED, SCN_USERLISTSELECTION, SCN_AUTOCSELECTION, SCN_URIDROPPED, */
/* SCN_AUTOCSELECTIONCHANGE */
Sci_Position length; /* SCN_MODIFIED */
Sci_Position linesAdded; /* SCN_MODIFIED */
int message; /* SCN_MACRORECORD */
uptr_t wParam; /* SCN_MACRORECORD */
sptr_t lParam; /* SCN_MACRORECORD */
Sci_Position line; /* SCN_MODIFIED */
int foldLevelNow; /* SCN_MODIFIED */
int foldLevelPrev; /* SCN_MODIFIED */
int margin; /* SCN_MARGINCLICK, SCN_MARGINRIGHTCLICK */
int listType; /* SCN_USERLISTSELECTION, SCN_AUTOCSELECTIONCHANGE */
int x; /* SCN_DWELLSTART, SCN_DWELLEND */
int y; /* SCN_DWELLSTART, SCN_DWELLEND */
int token; /* SCN_MODIFIED with SC_MOD_CONTAINER */
int annotationLinesAdded; /* SCN_MODIFIED with SC_MOD_CHANGEANNOTATION */
int updated; /* SCN_UPDATEUI */
int listCompletionMethod;
/* SCN_AUTOCSELECTION, SCN_AUTOCCOMPLETED, SCN_USERLISTSELECTION */
int characterSource; /* SCN_CHARADDED */
};
函数提示功能
在OnNotify()函数中增加接收触发事件消息
OOL CScintillaWnd::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
LPNMHDR pnmh = (LPNMHDR)lParam;
struct SCNotification* scn = (struct SCNotification*)lParam;
static int lastchar = 0;
switch(pnmh->code)
{
case SCN_DWELLSTART://将鼠标保持一定的停留期触发事件
{
OnDwellStart(scn);
break;
}
case SCN_DWELLEND://停留结束触发事件
{
OnDwellEnd(scn);
break;
}
break;
}
return CWnd::OnNotify(wParam, lParam, pResult);
}
鼠标保持处理函数
static const CString s_FuncList[] =
{
"Delay(",
"GetTick(",
};
static const CString s_FuncDesc[] =
{
//0-9
"Delay(毫秒)\n等待一段时间",
"GetTick()\n当前时间毫秒数",
};
void CScintillaWnd::OnDwellStart(_Inout_ SCNotification* pSCNotification)
{
//处理鼠标函数提示功能
static const char* pCallTipCurDesc = NULL; //当前提示的函数信息
TCHAR word[1000]; // 保存当前光标下的单词(函数名)
TextRange tr; // 用于SCI_GETTEXTRANGE命令
int pos = pSCNotification->position; // 取得当前光标位置
int startpos = SendDirect(SCI_WORDSTARTPOSITION, pos); // 当前单词起始位置
int endpos = SendDirect(SCI_WORDENDPOSITION, pos); // 当前单词终止位置
tr.chrg.cpMin = startpos; //设定单词区间,取出单词
tr.chrg.cpMax = endpos;
tr.lpstrText = word;
SendDirect(SCI_GETTEXTRANGE, 0, sptr_t(&tr));
if(CString(word).GetLength() < 1) return; //单词为空
for(size_t i = 0; i < sci_func_size; i++) //找找有没有我们认识的函数?
{
//函数名
CString sItem = s_FuncList[i].Left(s_FuncList[i].GetLength() - 1);
if(sItem.CompareNoCase(word) == 0) //找到了对应的函数
{
//找到了显示提示吧
pCallTipCurDesc = s_FuncDesc[i]; //当前提示的函数信息
CString sTip = pCallTipCurDesc;
//字符转换略
SendDirect(SCI_CALLTIPSHOW, pos, sptr_t(sTip.GetBuffer(0))); //显示这个提示
break;
}
}
}
鼠标保持结束处理函数
void CScintillaWnd::OnDwellEnd()
{
if(static_cast<BOOL>(SendDirect(SCI_CALLTIPACTIVE, 0, 0)) == 1) //SCI_CALLTIPACTIVE提示是否处于活动状态
SendDirect(SCI_CALLTIPCANCEL, 0, 0);//SCI_CALLTIPCANCEL取消任何显示的活动提示
}
OK,函数提示功能就实现了.
以下是函数的中文说明书下载链接