博客日历
2025年06月 | ||||||
一 | 二 | 三 | 四 | 五 | 六 | 七 |
26 | 27 | 28 | 29 | 30 | 31 | 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
存档
2025年03月 2024年
03月 04月 05月 2021年
01月 02月 11月 12月 2020年
02月 03月 04月 05月 06月 07月
09月 2018年
09月 2017年
01月 02月 07月 2016年
01月 04月 07月 08月 11月 12月
2015年
01月 02月 03月 05月 09月 10月
11月 2014年
01月 02月 03月 04月 05月 06月
07月 08月 09月 10月 11月 12月
2013年
01月 02月 03月 04月 05月 06月
07月 08月 09月 10月 11月 12月
2012年
01月 02月 03月 04月 05月 06月
07月 08月 09月 10月 11月 12月
2011年
01月 02月 03月 04月 05月 06月
07月 08月 09月 10月 11月 12月
2010年
01月 02月 03月 04月 05月 06月
07月 08月 09月 10月 11月 12月
2009年
03月 04月 05月 06月 07月 08月
09月 10月 11月 12月
语法高亮编辑控件Scintilla在MFC中的简单使用
项目中要使用代码编辑器,搜索之后,发现了强大的编辑器控件Scintilla。
1.简介
Scintilla是一款开源的语法高亮编辑器控件,官方网站:http://www.scintilla.org/。Scintilla是最优秀的编辑控件之一,实现了语法高亮,代码折叠,书签,自动完成等等诸多功能,速度快,源代码也比较好理解,易于扩展,易于增加对新语言的支持。 比较著名的scite,Notepad++,Notepad2都是基于Scintilla开发的。
Scintilla提供了Win32版本和Linux版本,在Windows下,它是一个窗体控件,对它的控制都通过发送消息来完成:
LRESULT SendMessage(HWND hWndScintilla,UINT Msg,WPARAM wParam,LPARAM lParam);
Scintilla提供了大量的消息API,每个消息可以带有0个、1个或2个参数。SendMessage函数中的消息,通常带有2个参数:wParam和lParam,没有使用的参数,则设置为0。对于大多数SCI_SETxxxxx设置类消息,都会有一个对应的SCI_GETxxxxx查询消息。
下面的图片是一个数控NC程序编辑器Demo:
2.在MFC中的简单使用
2.1 载入Scintilla链接库
首先,将SciLexer.dll复制到项目中。
a.在CwinApp下添加成员:
HMODULE m_hDll;
并初始化为NULL。
b.在InitInstance中载入DLL:
m_hDll = LoadLibrary(_T("SciLexer.dll")); if (m_hDll==NULL) { AfxMessageBox("LoadLibrary SciLexer.dll failure..."); }
c.在ExitInstance中卸载DLL:
if (m_hDll != NULL) { FreeLibrary(m_hDll); }
2.2 创建一个封装Scintilla的类 — CScintillaWnd
//------------------------------------------------------- // ScintillaWnd.h #pragma once //注意:这俩文件来自Scintilla的include目录 #include "Scintilla.h" #include "SciLexer.h" // CScintillaWnd class CScintillaWnd : public CWnd { DECLARE_DYNAMIC(CScintillaWnd) public: CScintillaWnd(); virtual ~CScintillaWnd(); protected: DECLARE_MESSAGE_MAP() public: virtual BOOL Create( DWORD dwExStyle, DWORD dwStyle,const RECT& rect, CWnd* pParentWnd, UINT nID); }; //------------------------------------------------------- // ScintillaWnd.cpp : 实现文件 #include "stdafx.h" #include "ColorTextBox.h" #include "ScintillaWnd.h" // CScintillaWnd IMPLEMENT_DYNAMIC(CScintillaWnd, CWnd) CScintillaWnd::CScintillaWnd() { } CScintillaWnd::~CScintillaWnd(){} BEGIN_MESSAGE_MAP(CScintillaWnd, CWnd) END_MESSAGE_MAP() // CScintillaWnd 消息处理程序 BOOL CScintillaWnd::Create(DWORD dwExStyle, DWORD dwStyle,const RECT& rect, CWnd* pParentWnd, UINT nID) { // TODO: 在此添加专用代码和/或调用基类 return CWnd::CreateEx(dwExStyle,"Scintilla","",dwStyle,rect,pParentWnd,nID); }
2.3 CScintillaWnd类的使用举例
将CScintillaWnd类的对象作为目标窗体类的一个成员,比如某个对话框CColorTextBoxDlg 。
class CColorTextBoxDlg : public CDialog { // 构造 public: CColorTextBoxDlg(CWnd* pParent = NULL); // 标准构造函数 // 对话框数据 enum { IDD = IDD_COLORTEXTBOX_DIALOG }; protected: virtual void DoDataExchange(CDataExchange* pDX); //.. public: CScintillaWnd m_ScintillaWnd; afx_msg int OnCreate(LPCreateSTRUCT lpCreateStruct); afx_msg void OnSize(UINT nType, int cx, int cy); };
a.在CcolorTextBoxDlg的OnCreate中创建Scintilla窗口:
m_ScintillaWnd.Create( WS_EX_CLIENTEDGE, WS_CHILD | WS_VISIBLE, CRect(0,0,lpCreateStruct->cx,lpCreateStruct->cy), this,10000);
b.在CcolorTextBoxDlg的OnSize中调整Scintilla窗口的大小:
m_ScintillaWnd.MoveWindow(0,0,cx,cy);
2.4 接收来自Scintilla控件的通知
当Scintilla控件发生事件时,会用WM_NOTITY消息通知父窗体。
2.4.1在MFC中
CxxxxWnd::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) { // TODO: 在此添加专用代码和/或调用基类 LPNMHDR pnmh = (LPNMHDR)lParam; struct SCNotification* scn = (struct SCNotification*)lParam; switch(pnmh->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; //case ... } }
2.4.2在SDK中
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;
2.5 例:行号的显示(MFC)
要显示行号,首先需要在m_ScintillaWnd创建后立即调用以下函数,并在Scintilla通知主窗口SCN_MODIFIED,SCN_ZOOM时调用:
C++代码
void UpdateLineNumberWidth(void)
{
char tchLines[32];
int iLineMarginWidthNow;
int iLineMarginWidthFit;
wsprintf(tchLines," %i ",
m_ScintillaWnd.SendMessage(SCI_GETLINECOUNT,0,0));
iLineMarginWidthNow = m_ScintillaWnd.SendMessage(
SCI_GETMARGINWIDTHN,0,0);
iLineMarginWidthFit = m_ScintillaWnd.SendMessage(
SCI_TEXTWIDTH,STYLE_LINENUMBER,(LPARAM)tchLines);
if (iLineMarginWidthNow != iLineMarginWidthFit)
{
m_ScintillaWnd.SendMessage(SCI_SETMARGINWIDTHN,0,
iLineMarginWidthFit);
}
}
BOOL OnNotify(
WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
LPNMHDR pnmh = (LPNMHDR)lParam;
struct SCNotification* scn = (struct SCNotification*)lParam;
switch(pnmh->code)
{
case SCN_MODIFIED:
//This notification is sent when the text or
//styling of the document changes or is about
//to change
case SCN_ZOOM:
//This notification is generated when the user
//zooms the display using the keyboard or the
//SCI_SETZOOM method is called.
UpdateLineNumberWidth();
break;
}
return CDialog::OnNotify(wParam, lParam, pResult);
}
2.6 例:设置文本,打开已有文件(MFC)
C++代码
void OnMenuFileOpen()
{
CFileDialog fDlg(TRUE);
if (fDlg.DoModal()==IDOK)
{
char *pBuffer;
CString strFilePath=fDlg.GetPathName();
CStdioFile stdFile(strFilePath,CFile::modeRead);
UINT nFileLength=stdFile.GetLength();
pBuffer=new char[nFileLength+1];
nFileLength=stdFile.Read(pBuffer,nFileLength);
stdFile.Close();
if (nFileLength>0)
{
if (m_ScintillaWnd.SendMessage(SCI_GETREADONLY,0,0))
{
m_ScintillaWnd.SendMessage(SCI_SETREADONLY,FALSE,0);
}
m_ScintillaWnd.SendMessage(SCI_CANCEL,0,0);
m_ScintillaWnd.SendMessage(SCI_SETUNDOCOLLECTION,0,0);
m_ScintillaWnd.SendMessage(SCI_EMPTYUNDOBUFFER,0,0);
//如果文本没有只读属性,则清除所有文字。
m_ScintillaWnd.SendMessage(SCI_CLEARALL,0,0);
//从所有行中删除标记,若markerNumber=-1,则删除所有标记。
m_ScintillaWnd.SendMessage(SCI_MARKERDeleteALL,
(WPARAM)-1,0);
m_ScintillaWnd.SendMessage(SCI_ADDTEXT,
nFileLength,(LPARAM)pBuffer);
m_ScintillaWnd.SendMessage(SCI_SETUNDOCOLLECTION,1,0);
m_ScintillaWnd.SendMessage(EM_EMPTYUNDOBUFFER,0,0);
m_ScintillaWnd.SendMessage(SCI_SETSAVEPOINT,0,0);
m_ScintillaWnd.SendMessage(SCI_GOTOPOS,0,0);
m_ScintillaWnd.SendMessage(SCI_CHOOSECARETX,0,0);
UpdateLineNumberWidth();
}
delete [] pBuffer;
}
}
2.7 例:设置默认字体以及字体大小(MFC)
C++代码
void SetDefaultFont(int nSize,const char* face)
{
m_ScintillaWnd.SendMessage(SCI_STYLESETFORE,
STYLE_DEFAULT, RGB(0x00,0x00,0x00));
m_ScintillaWnd.SendMessage(SCI_STYLESETBACK,
STYLE_DEFAULT, RGB(0xff,0xff,0xff));
m_ScintillaWnd.SendMessage(SCI_STYLESETSIZE,
STYLE_DEFAULT, nSize);
m_ScintillaWnd.SendMessage(SCI_STYLESETFONT,
STYLE_DEFAULT, reinterpret_cast<LPARAM>(face));
}
2.8 Lexer的编写
要实现一个新的语言(比如M语言)的语法高亮,需要在源代码级别对Scintilla做一点修改,并重新编译Scintilla:
2.8.1 加入一个源代码文件:
LexM.cxx
2.8.2 实现如下函数:
C++代码
static void ColouriseMDoc (
unsigned int startPos,
int length,
int initStyle,
WordList *keywordlists[],
Accessor &styler);
styler参数是一个Accessor对象,Lexer必须用这个对象来访问将要颜色化的文本。
Lexer用styler.SafeGetCharAt(i)来取得位置在i的字符;
startPos和length参数表示需要颜色化的文本的范围;
Lexer为所有在startPos到startPos+length范围内的字符决定恰当的颜色。
initStyle参数表示最初的状态, 也就是startPos之前一个字符的状态。状态也是表示指定范围内的文本的颜色。
注意: startPos位置的字符被事先假定为一行的开始, 如果新的一行终止了inisStyle状态Lexer应该进入默认状态(或者说任何状态应该在initStyle之后).
keywordlists参数指定Lexer应该识别的关键词,WordList对象包含识别关键词的方法,Present Lexers 用一个classifyWordLLL函数来识别关键词.这些函数展示怎么用keywordlists参数去识别关键词.
2.8.3 通过如下方式调用该函数:
C++代码
LexerModule lmM(SCLEX_M, ColouriseMDoc, "m", 0, asmWordListDesc);
2.8.4 在KeyWords.cxx文件中调用LINK_LEXER(lmM)宏。
3.备注
细节请参看Scintilla的帮助文档:http://www.scintilla.org/ScintillaDoc.html。
上一篇: 汶川大地震1周年祭
下一篇: 语法高亮编辑控件Scintilla在MFC中的简单使用之完整示例
分类:Win32/C++ 查看次数:23267 发布时间:2009/5/12 18:45:52