Scintilla 代码编辑组件开发技巧

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,函数提示功能就实现了.

以下是函数的中文说明书下载链接

【免费】Scintilla函数中文说明书资源-优快云文库

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值