Scintilla控件在Win32环境下的使用(一)

来源:互联网 发布:淘宝几天自动确认收货? 编辑:程序博客网 时间:2024/05/17 23:25

原本想要学习一下语法高亮功能,做一个像Notepad++一样的编辑器。

然后就兴冲冲的下载了Notepad++的开源代码准备开始看。

但是整个框架比较复杂,看了一会之后突然发现Notepad++使用的是Scintilla这个很强大的控件,而且也是开源的。所以最后决定在分析Notepad++源代码之前先使用一下Scintilla,然后研究一下Scintilla的源码。

下面是Scintilla 的官方网站:

http://www.scintilla.org/index.html

我们下载源代码。

然后准备编译。参考了下面这个博客:

http://blog.csdn.net/gnorth/article/details/7231513

我自己是win8 64位系统 vs2010

这里自己在编译makefile文件的时候出了一个错误:我使用了Visual Studio 命令提示(64位)下编译文件,结果编译出来之后的文件无法被vs识别。

一开始一直找不到错误,LoadLibrary 的返回值一直为0,后来用GetLastError()查看错误信息,才发现了原来是dll文件本身编译成了64位。

而我的程序是32位的,所以dll无法识别64位的dll。

后来用32位的 Visual Studio 命令提示重新编译出了32位的dll就对了。32位编译出来的dll是600多K, 而64位编译出来的是900多K。

具体编译的步骤:

打开Visual Studio 命令提示

进到下载好的scintilla文件目录下面的win32目录下面,

nmake -f scintilla.mak clean  //清理工程nmake -f scintilla.mak             //编译


接下来主要学习下面两篇文章,一篇是参考官方的文档,另外一篇是国人写的一个翻译文档。

http://www.scintilla.org/ScintillaDoc.html

http://www.cnblogs.com/superanyi/archive/2011/04/07/2008632.html


自己学习的时候是用Win32 SDK  C编写。

首先随便拉个Win32下面的应用程序,用windows程序设计里面的第一个对话框程序就好了。

我的目标是做出语法高亮,当然也不是限于这些,因为Scintilla是一个非常强大的库。


首先我们将编译好的SciLexer.dll放入当前目录中, 引入动态链接库:这里特别注意别犯像我这样的新手错误。

这个dll最大的功能就是进行语法解析 Lexer。

hmod = LoadLibrary("SciLexer.DLL");if (hmod==NULL){MessageBox(hwndParent,"The Scintilla DLL could not be loaded.","Error loading Scintilla",MB_OK | MB_ICONERROR);}
如果hmod不为0,那么说明我们成功引入了动态链接库。

下载的源码文件里面有Include文件,包含了一些头文件。这里我们将下面两个头文件放到当前目录下。

#include "SciLexer.h"#include "Scintilla.h"


接下来我们可以开始使用这个库里面的Scintilla类。我们可以创建一个窗口子类。

HWND hwndScintilla;        hwndScintilla = CreateWindowEx(0,"Scintilla","", WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_CLIPCHILDREN,10,10,500,400,hwndParent,(HMENU)GuiID, hInstance,NULL);

学过子窗口控件的同学对于创建上面的代码肯定都非常熟悉了。


接下来就是发送消息了。这里发送消息有两种方式。第一个方式就是SendMessage的方式,这种方式通俗易懂。第二种方式有点复杂。下面一一来介绍下:

SendMessage(hwndScintilla,sci_command,wparam,lparam);

like:

SendMessage(hwndScintilla,SCI_CREATEDOCUMENT, 0, 0);

这样就发送了窗口消息。我们可以在父窗口的窗口回调函数里面对消息进行处理:

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;

第二种方式有点复杂。我们首先看下官方文档给出的函数:

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);
自己也是新手,纯粹是为了觉得语法高亮好玩才玩的。自己的C语言功底不是很好,上面这段函数有点不太好理解。

int (*fn)(void*,int,int,int);
这里应该是定义了一个函数地址,这个函数有4个参数,返回值是int类型

fn = (int (__cdecl *)(void *,int,int,int))SendMessage(hwndScintilla,SCI_GETDIRECTFUNCTION,0,0);
这里定义了函数入口地址,相当于我们使用fn函数就是使用SendMessage函数。不知道这样讲对不对,还请大家指教。

其实这里自己感觉也解释不太清楚,想请大家帮忙指正理解。

比如我自己是这样定义的:

         int (*SendEditor)(void*,int,int,int);         //快速发送消息         SendEditor = (int (__cdecl *)(void *,int,int,int))SendMessage(             hwndScintilla,SCI_GETDIRECTFUNCTION,0,0);         ptr = (void *)SendMessage(hwndScintilla,SCI_GETDIRECTPOINTER,0,0);         canundo = SendEditor(ptr,SCI_CANUNDO,0,0);

以后自己就使用SendEditor,没有使用SendMessage了。

但是自己不理解的是:c应该没有重载 多态这些概念,我在使用SendEditor的时候里面必须写4个参数。感觉用起来也没方便多少。

自己C++没学多少。想请问下大家如何在C++下面实现该SendEditor的简洁方法?在此感谢大家。



原创粉丝点击