Scintilla教程(1): 入门介绍

  • Scintilla概述

Scintilla是一个富文本编辑器控件,支持GTKQTCocoa等多种UI框架。其功能接口的调用主要以消息传递的方式执行,比如载入文本文件,可以使用消息

SCI_SETTEXT(, const char *text)

该消息的作用是将Scintilla控件所显示的文本替换为消息体里面的text文本。对于消息的具体传递过程,不同的平台(GTKQTCocoa等)对应不同的调用方法,在后续的QT开发会做详细介绍,并给出使用样例。除了执行普通编辑控件操作的消息外,Scancilla还支持控制语法样式、折叠、标记、自动完成和调用提示。

目前Scintilla对从右向左的语言(如阿拉伯语和希伯来语)的支持尚未完善,可以正确显示,但是编辑操作可能会有问题。

SciTE编辑器是Scintilla开发组为了展示Scintilla功能所开源的一款软件,几乎用到了Scintilla的所有接口与功能,可以用作开发参考。

Scintilla教程(1): 入门介绍_第1张图片

SciTE编辑器 图片引自再推荐一款编辑器:SciTE

  • Scintilla核心接口文件介绍

Scintilla的类型定义以及接口定义头文件分别是ScintillaTypes.h, ScintillaMessages.h以及ScintillaStructures.h

其中ScintillaTypes.h定义了消息中的各种属性枚举类型,以自动折行方式(Line wrapping)为例,在使用编辑器过程中,经常有行文字过长的情况,此时需要通过水平滚动条来看全完整一行内容,给使用者带来很大的不便。因此主流文本编辑器(如notepad++)都会提供自动折行功能。ScintillaTypes.h中的枚举类型Wrap即用于控制自动折行的方式:

enum class Wrap {
    None = 0,               //非自动折行
    Word = 1,               //以完整单词为单位做折行
    Char = 2,               //以单个字符为单位做折行
    WhiteSpace = 3,         //以空格为单位做折行
};

在开发过程中,开发者可调用消息SCI_SETWRAPMODE(int wrapMode)完成自动折行功能,其中参数wrapMode即使用上述Wrap枚举类型。

ScintillaMessages.h中定义了所有消息枚举值(Message),这些枚举值应用在Scintilla代码文件Editor.cxx中:

sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) 

ScintillaMessages.h中的消息与开发者经常使用的消息命名不同,比如还是以自动折行方式(Line wrapping)为例,开发者使用消息为SCI_SETWRAPMODE,而对应ScintillaMessages.h中的消息则是Message::SetWrapMode。这是由于Scintilla提供给开发者的接口头文件为Scintilla.h,其采用宏定义的方式,定义了所有的消息,SCI_SETWRAPMODE在其中定义为:

#define SCI_SETWRAPMODE 2268

该宏定义的消息与ScintillaMessages.h中枚举消息SetWrapMode = 2268的值相等,因此在开发者发送的消息SCI_SETWRAPMODE同样可以进入Editor::WndProc函数里面case Message::SetWrapMode的处理逻辑中。

ScintillaStructures.h中定义了通知类型,主要用于将Scintilla控件中接收到的如鼠标点击,键盘输入等消息传递出去。以鼠标双击为例,Scintilla控件在接收到鼠标双击操作后,将双击位置以及键盘当前输入(如按住Ctrl双击)传递给外部容器。

void Editor::NotifyDoubleClick(Point pt, KeyMod modifiers) {
    NotificationData scn = {};
    scn.nmhdr.code = Notification::DoubleClick;
    scn.line = LineFromLocation(pt);
    scn.position = PositionFromLocation(pt, true);
    scn.modifiers = modifiers;
    NotifyParent(scn);
}

  • Scintilla消息调用方法

Scintilla功能接口的调用主要以消息传递的方式执行,在其官网的说明文档中,Scintilla给出了全部的消息说明。

比如自动折行,可调用消息:

SCI_SETWRAPMODE(int wrapMode)

再比如获取某一行的字符串,可调用消息:

SCI_GETLINE(line line, char *text)

在实际的开发中,具体的调用接口为ScintillaBase.hScintillaBase类(开发者可以通过继承该类的方式进行二次开发)的成员函数:

sptr_t ScintillaBase::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) ;

其中iMessage为消息类型,即可以设值为上面提到的SCI_SETWRAPMODE以及SCI_GETLINEwParamlParam是相关的附加参数。

SCI_SETWRAPMODE(int wrapMode)的调用方式具体为:

WndProc(SCI_SETWRAPMODE, static_cast(Wrap::Word));

SCI_GETLINE(line line, char *text)的调用方式具体为:

WndProc(SCI_GETLINE, static_cast(line), reinterpret_cast(text));

WndPro函数也具有返回值,一般返回为position,比如获取光标所在当前行,调用消息SCI_GETCURLINE(position length, char *text NUL-terminated) ,其返回值为光标所在的行数,入参text则保存了当前行的字符内容。

注:Scintilla中有些消息带的参数为,这种情况将其赋值为0即可,具体调用方式为(以SCI_SETTEXT(, const char *text)为例):

WndProc(SCI_SETTEXT, static_cast(0), reinterpret_cast(text)))

  • scintilla事件处理方法

Scintilla在ScintillaStructures.h中定义了通知事件数据类型,如下所示:

struct NotificationData {
    NotifyHeader nmhdr;
    Position position;
    /* SCN_STYLENEEDED, SCN_DOUBLECLICK, SCN_MODIFIED, SCN_MARGINCLICK, */
    /* SCN_NEEDSHOWN, SCN_DWELLSTART, SCN_DWELLEND, SCN_CALLTIPCLICK, */
    /* SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, SCN_HOTSPOTRELEASECLICK, */
    /* SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
    /* SCN_USERLISTSELECTION, SCN_AUTOCSELECTION */
​
    int ch;
    /* SCN_CHARADDED, SCN_KEY, SCN_AUTOCCOMPLETED, SCN_AUTOCSELECTION, */
    /* SCN_USERLISTSELECTION */
    KeyMod modifiers;
    /* SCN_KEY, SCN_DOUBLECLICK, SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, */
    /* SCN_HOTSPOTRELEASECLICK, SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
​
    ModificationFlags modificationType; /* SCN_MODIFIED */
    const char *text;
    /* SCN_MODIFIED, SCN_USERLISTSELECTION, SCN_AUTOCSELECTION, SCN_URIDROPPED */
​
    Position length;        /* SCN_MODIFIED */
    Position linesAdded;    /* SCN_MODIFIED */
    Message message;    /* SCN_MACRORECORD */
    uptr_t wParam;  /* SCN_MACRORECORD */
    sptr_t lParam;  /* SCN_MACRORECORD */
    Position line;      /* SCN_MODIFIED */
    FoldLevel foldLevelNow; /* SCN_MODIFIED */
    FoldLevel foldLevelPrev;    /* SCN_MODIFIED */
    int margin;     /* SCN_MARGINCLICK */
    int listType;   /* SCN_USERLISTSELECTION */
    int x;          /* SCN_DWELLSTART, SCN_DWELLEND */
    int y;      /* SCN_DWELLSTART, SCN_DWELLEND */
    int token;      /* SCN_MODIFIED with SC_MOD_CONTAINER */
    Position annotationLinesAdded;  /* SCN_MODIFIED with SC_MOD_CHANGEANNOTATION */
    Update updated; /* SCN_UPDATEUI */
    CompletionMethods listCompletionMethod;
    /* SCN_AUTOCSELECTION, SCN_AUTOCCOMPLETED, SCN_USERLISTSELECTION, */
    CharacterSource characterSource;    /* SCN_CHARADDED */
};

该数据结构主要用于将Scintilla控件中接收到的如鼠标点击,键盘输入等消息传递出去。

以文本内容的修改为例,当有增删改的动作后,Scintilla控件即向外部容器发送待保存事件:Notification::SavePointLeft。此时外部容器可以做对应处理,比如可以将文件标题最后增加*号,表示需要保存。发送相关事件的代码在Editor.cxx中:

void Editor::NotifySavePoint(bool isSavePoint) {
    NotificationData scn = {};
    if (isSavePoint) {
        scn.nmhdr.code = Notification::SavePointReached;
    } else {
        scn.nmhdr.code = Notification::SavePointLeft;       //文本内容有修改后进入该语句
    }
    NotifyParent(scn);      //此处向外部容器发送事件
}

上面代码中的NotifyParent(scn)既是向外部容器发送事件的接口函数。在Editor类中,定义了如下纯虚函数:

virtual void NotifyParent(Scintilla::NotificationData scn) = 0;

因此在实际的开发中,开发者可以通过继承ScintillaBase类的方式进行二次开发。(ScintillaBase类继承Editor类)

你可能感兴趣的:(Scintilla,c++)