Scintilla使用指南Scintilla是一个免费的源代码编辑控件,它完全开放源代码,并且提供一个license允许用户自由地将它用在开源软件或是商业软件中。
我是在做毕业课题的时候发现的这个编辑控件,使用后发现它实在是强大和稳定,作为源代码编辑控件,我们能在普通的的文本编辑控件中能看到的功能,Scintilla都完全能够实现,而且,它还能够提供很多编辑和调试源代码时有用的特殊功能。包括语法高亮显示,错误指示,代码自动完成以及代码提示等。而且在左边的空白处(margin),可以显示调试代码中非常有用的显示断点以及显示当前运行行等功能。而且,自定义风格的功能比其他大部分编辑器控件都开放,它允许用户自定义不同类型下的字体,是否粗体,是否斜体,前景色和背景色,支持大量的字体。举个例子,在设置C/C++编辑模式后,你可以定义注释语句类型的颜色,字体,大小等等,同样,可以自定义关键字类型的颜色,字体,大小……诸如此类,这样给用户极大的配置的自由。
据Scintilla的网站上发布的消息,Scitilla将在以后的开发中,更加灵活,健壮,更好地表现在.Net和java虚拟机中运行,就这一点,可以看出Scitilla项目就是一个非常有活力的项目,其开发团队对它非常有激情,这也使我们——这些用户从中受益。
据作者介绍,开发Scintilla的动机是来自他对Richedit的失望,在Richedit中,样式的改变被看作是文档的一种改变,从而会被记录到undo的堆栈中,并且设置的文档对象的修改标记。这对源代码编辑是非常不合适的,改变关键字类型的颜色或是运算符的颜色,这不应该看作是文档的修改,也不应该能够通过undo/redo来返回/前进。我对此深有感触,如果是Richedit来做源代码编辑的控件,那将有太多的东西需要自己编写代码实现了,选择Scintilla,将是一个明智的选择,省时,省力,安全,可靠。
Scintilla目前提供了Win32版本和Linux版本。在Linux中使用的是GTK+,已经在 Windows95,nt4.0, Windows2000, windows XP以及RedHat Linux8和9中的GTK+1.2和2.0中测试运行正常。这是一个跨平台的控件,也是我对其非常欣赏的原因之一。下面我的主要论述的还是在 windows + VC下如何使用这个控件,但是其他平台/编译工具下也大同小异,触类旁通吧。
简介:
Scintilla的windows版本就是一个窗体控件。它的主要编程接口是通过窗体消息来传送的。你要实现什么功能,向控件发送一个消息就可以了,当需要从控件得到什么信息,接受WM_NOTIFY消息即可,可以从它带的参数中获得大量当前控件的信息,比如是否已经修改文字了,是否正在点击左边的边框等等。但是,实际上在MFC编程中,通过消息的方式来控制控件还是非常麻烦的,因为这些消息的大部分都是自定义消息,不便于记忆。所以一般的做法就是将这些消息的调用封装成一个窗体类,这样调用方便多了。除了能实现一般编辑控件能实现的功能外,scintilla还能实现语法高亮,代码折叠,书签,自动完成,语句提示等等功能。你完全可以不用学习标准编辑控件CEDIT或者是 RichEdit,scintilla提供了协调一致的API口,这些都是它的优点之处。
事实上,scintilla开发组同时也用这个控件开发了一个编辑软件SciTE,它百分百的实现了 scintilla的全部功能,如果你对scintilla非常感兴趣,但又不知它到底能做到那些功能的活,当一个SciTE,使用一下就完全明白了。同时,SciTE也是开源软件,学习它的代码,就是学习scintilla的使用方法。在scintilla的文档中,就说明了,这个文档只是独立地讲解各个消息的使用方法,功能和参数,并不能讲解如何把它们连接起来组成一个实用的编辑器,要想知道如何实现某些特定功能,还是看看SciTE是如何实现的。我也看过SciTE的代码,可读性还是不错的,可惜我是没有耐心的人,也就读了几个函数,大体了解了一下,如果你想用好这个控件,多读读SciTE的源码还是不错的。
scintilla的消息就用SendMessage函数发送,它提供两个头文件:Scintilla.h和 SciLexer.h,消息号的宏定义都在这里,而且还有很多要用到的结构体,类型等等的定义。消息带的两个参数wParam和lParam是要经常用到的,也许会用到一个,两个,或者无需参数。但建议你最好在使用的时候把不用的参数都赋予0值,因为如果以后扩充消息功能,用到了某个参数,赋值能防止程序的崩溃。
通常参数的类型如下:
bool int const char* char* colour <unused>
其他的类型不用多说,至于color类型,是用于描述颜色的,它实际上就是一个整数,计算方法是:red| (green << 8)|(blue << 16), red,green,blue是8位2进制数,也就是2位16进制数。很容易就能实现256色的调配。至于<unused>,就是说这个参数在这个消息中不用,可以赋为0值。
下面的讲解的重点是放在VC+MFC的环境中,因为我一直在这个环境下开发东西,要是用SDK编程也一样的,只是用到了更多的API,至于编译器,VC也好,GCC也好,我觉得没什么大问题,我就曾经用GDB调试SciTE的源码,来了解scintilla如何使用的,Linux平台下的GTK+编程我没尝试过,从文档上看,也是用消息的方式来控制控件,用接受消息的方式来获得控件的信息。
下面我就如何封装scintilla成为一个窗体类,如何在程序中使用它的功能一一讲解,水平有限,而且现在还在上学中,可能写得比较慢,呵呵,谅解。
如何使用scinitlla控件呢?scintilla控件需要两个头文件,Scintilla.h和SciLexer.h,这里定义了消息宏,所用到的数据结构类型等等。在所要用到的cpp文件中包括这两个头文件即可。
scinitlla控件与主程序交互通信是通过消息传递的。在窗体类中,创建一个scinitlla控件,然后发送消息给控件,以达到不同的目的。有的时候,我们也需要控件的反馈,比如当用户点击编辑器左边栏时,我们希望控件能通知父窗体,这时,父窗体接收到一个WM_NOTIFY消息,它的参数lParam可以转化为结构体SCNotification的指针类型,结构体SCNotification是由控件头文件定义的,该结构体定义如下:
struct SCNotification {
struct NotifyHeader nmhdr;
int position;
// SCN_STYLENEEDED, SCN_MODIFIED, SCN_DWELLSTART,
// SCN_DWELLEND, SCN_CALLTIPCLICK,
// SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK
int ch; // SCN_CHARADDED, SCN_KEY
int modifiers; // SCN_KEY, SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK
int modificationType; // SCN_MODIFIED
const char *text; // SCN_MODIFIED
int length; // SCN_MODIFIED
int linesAdded; // SCN_MODIFIED
int message; // SCN_MACRORECORD
uptr_t wParam; // SCN_MACRORECORD
sptr_t lParam; // SCN_MACRORECORD
int line; // SCN_MODIFIED
int foldLevelNow; // SCN_MODIFIED
int foldLevelPrev; // SCN_MODIFIED
int margin; // SCN_MARGINCLICK
int listType; // SCN_USERLISTSELECTION
int x; // SCN_DWELLSTART, SCN_DWELLEND
int y; // SCN_DWELLSTART, SCN_DWELLEND
};
上面的SCN_MODIFIED, SCN_MARGINCLICK,SCN_STYLENEEDED等都是控件定义不同的消息宏,通过该结构体,可以知道控件通知父窗体的内容,
具体的代码实现会在下面的内容叙述的。
在创建控件之前,必不可少的一步就是加载动态库scilexer.dll,在WinApp类的InitInstance()方法中,加入
m_hDll = LoadLibrary(_T("SciLexer.dll"));
其中m_hDll是定义的App类的成员变量,同时,在ExitInstance() 方法中,加入
// unload scintilla dll
if (m_hDll != NULL)
FreeLibrary(m_hDll);
这样才能使用功能强大的scintilla控件,否则是会出现无法创建控件的错误的。
那么如何创建scintilla控件?在MFC中,我们一般的做法是建立一个CWND窗体类,封装与scintilla控件通信的一系列实现,然后在视图类中加一个该窗体类的成员变量,通过窗体类来实现控件的各种操作,如创建、初始化等。这时起封装作用的窗体类看作是控件,这就是在设计模式中称为PROXY的模式。
我们建立一个CScintillaWnd类,如下:
class CScintillaWnd : public CWnd
{
public:
CScintillaWnd();
virtual ~CScintillaWnd();
BOOL Create (LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID);
}
#define STR_SCINTILLAWND _T("Scintilla")
BOOL CScintillaWnd::Create (LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
{
return CWnd::CreateEx(WS_EX_CLIENTEDGE, STR_SCINTILLAWND, lpszWindowName, dwStyle, rect, pParentWnd,(UINT)nID))
}
这样就创建了控件,在视图类中,加入CScintillaWnd类型的成员变量,例如:
private:
CScintillaWnd m_wndScintilla;
在视图类的OnCreate()函数中,加入:
if (!m_wndScintilla.Create(_T("Title"), WS_CHILD | WS_VISIBLE, CRect(0,0,0,0), this, 10000))
{
AfxMessageBox("can't create scintilla!");
return -1;
}
return 0;
同时,在OnSize()函数中,加入:
if (m_wndScintilla.GetSafeHwnd())
m_wndScintilla.MoveWindow(0, 0, cx, cy);
这样保证控件与视图对齐,否则会发生找不到控件的现象。
执行了上述几步之后,在视图类中,应该可以看到scintilla控件的编辑窗口,现在就可以在该窗口上输入文本了。