mfc c语言 编辑器,语法高亮编辑控件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:
C++代碼
m_hDll?=?LoadLibrary(_T("SciLexer.dll"));
if(m_hDll==NULL)
{
AfxMessageBox("LoadLibrary?SciLexer.dll?failure...");
}
c.在ExitInstance中卸載DLL:
C++代碼
if?(m_hDll?!=?NULL)
{
FreeLibrary(m_hDll);
}
2.2 創建一個封裝Scintilla的類 — CScintillaWnd
C++代碼
//-------------------------------------------------------
//?ScintillaWnd.h
#pragma?once
//注意:這倆文件來自Scintilla的include目錄
#include?"Scintilla.h"
#include?"SciLexer.h"
//?CScintillaWnd
classCScintillaWnd?:publicCWnd
{
DECLARE_DYNAMIC(CScintillaWnd)
public:
CScintillaWnd();
virtual~CScintillaWnd();
protected:
DECLARE_MESSAGE_MAP()
public:
virtualBOOLCreate(
DWORDdwExStyle,DWORDdwStyle,constRECT&?rect,
CWnd*?pParentWnd,UINTnID);
};
//-------------------------------------------------------
//?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?消息處理程序
BOOLCScintillaWnd::Create(DWORDdwExStyle,DWORDdwStyle,constRECT&?rect,?CWnd*?pParentWnd,UINTnID)
{
//?TODO:?在此添加專用代碼和/或調用基類
returnCWnd::CreateEx(dwExStyle,"Scintilla","",dwStyle,rect,pParentWnd,nID);
}
2.3 CScintillaWnd類的使用舉例
將CScintillaWnd類的對象作為目標窗體類的一個成員,比如某個對話框CColorTextBoxDlg 。
C++代碼
class?CColorTextBoxDlg?:?public?CDialog
{
//?構造
public:
CColorTextBoxDlg(CWnd*?pParent?=?NULL);//?標準構造函數
//?對話框數據
enum{?IDD?=?IDD_COLORTEXTBOX_DIALOG?};
protected:
virtualvoidDoDataExchange(CDataExchange*?pDX);
//..
public:
CScintillaWnd?m_ScintillaWnd;
afx_msgintOnCreate(LPCreateSTRUCT?lpCreateStruct);
afx_msgvoidOnSize(UINTnType,intcx,intcy);
};
a.在CcolorTextBoxDlg的OnCreate中創建Scintilla窗口:
C++代碼
m_ScintillaWnd.Create(
WS_EX_CLIENTEDGE,
WS_CHILD?|?WS_VISIBLE,
CRect(0,0,lpCreateStruct->cx,lpCreateStruct->cy),
this,10000);
b.在CcolorTextBoxDlg的OnSize中調整Scintilla窗口的大小:
C++代碼
m_ScintillaWnd.MoveWindow(0,0,cx,cy);
2.4 接收來自Scintilla控件的通知
當Scintilla控件發生事件時,會用WM_NOTITY消息通知父窗體。
2.4.1在MFC中
C++代碼
CxxxxWnd::OnNotify(WPARAM?wParam,?LPARAM?lParam,?LRESULT*?pResult)
{
//?TODO:?在此添加專用代碼和/或調用基類
LPNMHDR?pnmh?=?(LPNMHDR)lParam;
structSCNotification*?scn?=?(structSCNotification*)lParam;
switch(pnmh->code)
{
caseSCN_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中
C++代碼
NMHDR?*lpnmhdr;
//[...]
caseWM_NOTIFY:
lpnmhdr?=?(LPNMHDR)?lParam;
if(lpnmhdr->hwndFrom==hwndScintilla)
{
switch(lpnmhdr->code)
{
caseSCN_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)
{
chartchLines[32];
intiLineMarginWidthNow;
intiLineMarginWidthFit;
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);
}
}
BOOLOnNotify(
WPARAMwParam,LPARAMlParam,LRESULT*?pResult)
{
LPNMHDR?pnmh?=?(LPNMHDR)lParam;
structSCNotification*?scn?=?(structSCNotification*)lParam;
switch(pnmh->code)
{
caseSCN_MODIFIED:
//This?notification?is?sent?when?the?text?or
//styling?of?the?document?changes?or?is?about
//to?change
caseSCN_ZOOM:
//This?notification?is?generated?when?the?user
//zooms?the?display?using?the?keyboard?or?the
//SCI_SETZOOM?method?is?called.
UpdateLineNumberWidth();
break;
}
returnCDialog::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);
UINTnFileLength=stdFile.GetLength();
pBuffer=newchar[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(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.備注
總結
以上是生活随笔為你收集整理的mfc c语言 编辑器,语法高亮编辑控件Scintilla在MFC中的简单使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C语言开发windows桌面程序,开发
- 下一篇: c语言hellowwo所占字节数,哪个懂