📄 syneditview.cpp
字号:
////////////////////////////////////////////////////////////
// 文件: SynEditView.cpp
// 版本: 1.0.0.0
// 创建 : 2002年1月15日
//
// 作者: 郑旭
// E-mail: happymood@163.net
//
// CSynEditView语法编辑视实现代码
//
// 你可以自由使用或是改变CSynEditView的代码以适应你的需要,
// 但是请保留这段文字。
////////////////////////////////////////////////////////////
//本人欲在北京求一软件开发职位,期望月薪3000元以上,
//若您是招聘单位并对本人有意,请与本人联系。
/*//////////////////////////////////////////////////////////
设计思路:
假设SynCtrl即是隐藏在CRichEditView后面可以用GetRichEditCtrl函数取得的控制。
SynEditView可看作覆盖在SynCtrl表面的一层不透明的画布,在程序中我们自己作画,
再将画出来的内容覆盖在SynCtrl表面,即可作成语法关键字编辑效果。
虽然在程序中重载OnPaint函数但不作任何操作带来的后果是SynCtrl不再重画,但是
隐藏在SynCtrl后面的内容仍然存在,我们可以通过GetLine取得其文本信息,也可以
通过GetFont取得其字体信息!我们可以取出这些信息进行加工,再将加工后的东西显
示出来。通过仔细的调整各个参数,使得画出来的东西与不重载SynCtrl的OnPaint函
数前SynCtrl画出来的东西完全重合,但只是把其中是关键字的部分进行着色,即可达
到完美的语法编程器的效果。
/*//////////////////////////////////////////////////////////
#include "stdafx.h"
#include <winver.h>
#include <malloc.h>
#include "SynEditView.h"
const COOKIE_COMMENT = 0x0002;
const COOKIE_EXT_COMMENT = 0x0004;
const COOKIE_STRING = 0x0008;
const COOKIE_CHAR = 0x0010;
//定义颜色块宏
#define DEFINE_BLOCK(pos, color) \
ASSERT((pos) >= 0 && (pos) <= nLength);\
if (ColorInfo != NULL)\
{\
if (nActualItems == 0 || ColorInfo[nActualItems - 1].Pos <= (pos)) {\
ColorInfo[nActualItems].Pos = (pos);\
ColorInfo[nActualItems].Color = (color);\
nActualItems ++;\
}\
}
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CSynEditView
IMPLEMENT_DYNCREATE(CSynEditView, CSynEditView)
BEGIN_MESSAGE_MAP(CSynEditView, CSynEditView)
//{{AFX_MSG_MAP(CSynEditView)
ON_WM_CREATE()
ON_WM_HSCROLL()
ON_WM_VSCROLL()
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CSynEditView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CSynEditView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CSynEditView::OnFilePrintPreview)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CSynEditView construction/destruction
CSynEditView::CSynEditView()
{
m_nLanguage = _CPP;
m_clrBkColor = RGB(255, 255, 255);
m_clrCommentColor = RGB(0, 128, 0);
m_clrSyntaxColor = RGB(0, 0, 255);
m_clrNormalColor = RGB(0, 0, 0);
m_clrStringColor = RGB(200, 0, 0);
m_clrCharColor = RGB(200, 0, 0);
m_clrNumberColor = RGB(255, 0, 0);
m_clrBKSelText = RGB(0, 0, 128);
m_nTabSize = 4;
m_nParseArraySize = 0;
m_nLeftMargin = 1;
m_nTopMargin = 1;
m_bAllowDraw = TRUE;
m_bRealReturn = TRUE;
m_bTracking = FALSE;
m_pdwParseCookies = NULL;
m_rcClient = NULL;
m_pCacheBitmap = NULL;
}
CSynEditView::~CSynEditView()
{
if (m_pCacheBitmap != NULL)
delete m_pCacheBitmap;
if (m_pdwParseCookies != NULL)
delete m_pdwParseCookies;
}
BOOL CSynEditView::PreCreateWindow(CREATESTRUCT& cs)
{
//装入rich edit version 2.0
if (LoadLibraryA("RICHED20.DLL") == NULL)
{
AfxMessageBox(_T("Fail to load \"riched20.dll\"."),
MB_OK | MB_ICONERROR);
PostMessage(WM_QUIT,0,0);
return FALSE;
}
m_strClass = RICHEDIT_CLASSA; //for 2.0 class
return CSynEditView::PreCreateWindow(cs);
}
void CSynEditView::OnInitialUpdate()
{
CSynEditView::OnInitialUpdate();
SetMargins(CRect(720, 720, 720, 720));
SelectLanguage( _CPP );
::GetObject(GetStockObject(SYSTEM_FONT), sizeof(LOGFONT), &m_lf);
m_lf.lfWeight = FW_NORMAL;
m_lf.lfHeight = 0xfffffff2;
m_lf.lfCharSet = GB2312_CHARSET;
strcpy(m_lf.lfFaceName, _T("Fixedsys"));
SetSynEditViewFont(m_lf);
SendMessage(EM_SETUNDOLIMIT, 1000, 0);
GetDocument()->m_bRTF = FALSE; //只处理文本
SetWrapMode(WrapNone);
SendMessage(EM_SETTEXTMODE, TM_PLAINTEXT|TM_MULTILEVELUNDO|TM_SINGLECODEPAGE, 0);
}
/////////////////////////////////////////////////////////////////////////////
// CSynEditView printing
BOOL CSynEditView::OnPreparePrinting(CPrintInfo* pInfo)
{
// default preparation
return DoPreparePrinting(pInfo);
}
/////////////////////////////////////////////////////////////////////////////
// CSynEditView diagnostics
#ifdef _DEBUG
void CSynEditView::AssertValid() const
{
CSynEditView::AssertValid();
}
void CSynEditView::Dump(CDumpContext& dc) const
{
CSynEditView::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CSynEditView message handlers
void CSynEditView::LoadFile(CString strFile)
{
ASSERT(this);
CFile* pInputFile = NULL;
try
{
pInputFile = new CFile(strFile, CFile::modeRead | CFile::shareDenyNone);
EDITSTREAM strm;
strm.dwCookie = (DWORD) pInputFile;
strm.pfnCallback = EditStreamCallbackReadFromFile;
long lResult = GetRichEditCtrl().StreamIn(SF_TEXT, strm);
pInputFile->Close();
delete pInputFile;
}
catch (CFileException* pEx)
{
pEx->Delete();
}
GetRichEditCtrl().SetModify( FALSE );
}
//设定编辑器字体
void CSynEditView::SetSynEditViewFont(LOGFONT lf)
{
m_lf = lf;
SetSynCtrlFont();
SetSynEditViewTabSize(m_nTabSize);
}
void CSynEditView::SetSynCtrlFont()
{
CString str;
GetWindowText(str);
BOOL bModify = GetRichEditCtrl().GetModify();
m_font.DeleteObject();
m_font.CreateFontIndirect(&m_lf);
SetFont(&m_font);
CalcEditorInfo();
SetSynEditViewMargin(m_nCharNumberWidth, 0);
SetWindowText(str);
GetRichEditCtrl().SetModify(bModify);
}
//设定编辑器的Tab宽度,以空格为标准进行计算
void CSynEditView::SetSynEditViewTabSize(int nSize)
{
ResetParseCookie();
CString str;
GetWindowText(str);
CRichEditCtrl &SynCtrl = GetRichEditCtrl();
BOOL bModify = SynCtrl.GetModify();
SetSynCtrlTabSize(nSize);
SetWindowText(str);
SynCtrl.SetModify(bModify);
}
//改变RichEditCtrl的默认Tab宽度
void CSynEditView::SetSynCtrlTabSize(int nSize)
{
CRichEditCtrl &SynCtrl = GetRichEditCtrl();
//设置TAB间隔
CDC *pdc = GetDC();
PARAFORMAT pf ;
pf.cbSize = sizeof(PARAFORMAT);
pf.dwMask = PFM_TABSTOPS ;
pf.cTabCount = MAX_TAB_STOPS;
SynCtrl.GetParaFormat( pf );
int nSynCtrlTabSize = pf.rgxTabs[0];
if(nSynCtrlTabSize == 0)
nSynCtrlTabSize = 720;
int nNewTab;
nNewTab = int(nSynCtrlTabSize * 1.0 * nSize * m_nCharSpaceWidth / m_nCharTabWidth);
pf.cTabCount = MAX_TAB_STOPS;
pf.dwMask = PFM_TABSTOPS;
for( int itab = 0; itab < pf.cTabCount; itab++ )
pf.rgxTabs[itab] = (itab+1) * nNewTab ;
SetParaFormat( pf );
m_nTabSize = nSize;
}
void CSynEditView::LoadText(CString &strText)
{
ASSERT(this);
ResetParseCookie();
SetWindowText(strText);
GetRichEditCtrl().SetModify( FALSE );
}
//根据指定行在指定的矩形区域画出语法加亮的文本
void CSynEditView::DrawSingleLineColorText( CDC *cacheDC, int nLine, CRect rcLine)
{
CRect rectforspace(rcLine);
CRect rect(rcLine);
CFont cf;
cf.CreateFontIndirect(&m_lf);
CFont *pOldFont = cacheDC->SelectObject(&cf);
CString strnewline=_T(""), strtmp=_T(""), strLine;
BOOL bRealReturn = GetLineString(nLine, strLine); //取指定行文本,并返回是否为硬回车标志
int nTabNumber = 0;
int npos = strLine.Find(_T("\t"));
//将所有的Tab转化为相应数量的空格
while(npos!=-1) {
strtmp = strLine.Left(npos);
int nlen = strtmp.GetLength();
nlen %= m_nTabSize;
nlen = m_nTabSize - nlen;
CString strNewTab(0x20, nlen);
strtmp+=strNewTab;
strnewline+=strtmp;
strLine=strLine.Right(strLine.GetLength()-npos-1);
npos = strLine.Find(_T("\t"));
}
strnewline+=strLine;
strLine=strnewline;
int nLength = strLine.GetLength();
CSize size;
int nActualItems = 0;
COLORINFO *ColorInfo = (COLORINFO *)_alloca( sizeof(COLORINFO) * (nLength + 1) );
DWORD dwCookie = GetParseCookie(nLine-1);
CString str;
if( m_bRealReturn )
dwCookie &= COOKIE_EXT_COMMENT;
m_bRealReturn = bRealReturn;
dwCookie = ParseLine(dwCookie, strLine, ColorInfo, nActualItems);
m_pdwParseCookies[nLine] = dwCookie;
COLORREF clr;
int nlen;
if (nActualItems > 0)
{
ASSERT(ColorInfo[0].Pos >= 0 && ColorInfo[0].Pos <= nLength);
for (int I = 0; I < nActualItems; I ++)
{
nlen = ColorInfo[I + 1].Pos - ColorInfo[I].Pos;
if( I == nActualItems - 1 )
str = strLine.Mid(ColorInfo[I].Pos, strLine.GetLength() - ColorInfo[I].Pos);
else
str = strLine.Mid(ColorInfo[I].Pos, nlen);
if(str.IsEmpty())
continue;
clr = GetColor(ColorInfo[I].Color);
JudgeInSeletioAndDrawText( cacheDC, rcLine, str, m_clrBkColor, clr );
}
}
cacheDC->SelectObject(pOldFont);
}
void CSynEditView::SetWrapMode(int nWrapMode)
{
ASSERT(this);
m_nWordWrap = nWrapMode;
CSynEditView::WrapChanged();
ResetParseCookie();
if(m_nWordWrap == WrapNone)
{
GetRichEditCtrl().ShowScrollBar(SB_BOTH, TRUE);
}
else
{
GetRichEditCtrl().ShowScrollBar(SB_HORZ, FALSE);
}
}
int CSynEditView::GetLinesTop(int nline)
{
CRichEditCtrl &SynCtrl = GetRichEditCtrl();
if( nline > SynCtrl.GetLineCount()-1 ) {
int nOffset = SynCtrl.LineIndex( nline-1 );
CPoint p = SynCtrl.GetCharPos( nOffset );
return p.y+m_nLineHeight;
}
int nOffset = SynCtrl.LineIndex( nline );
CPoint p = SynCtrl.GetCharPos( nOffset );
return p.y;
}
int CSynEditView::GetCurrentLine()
{
CRichEditCtrl &SynCtrl=GetRichEditCtrl();
CHARRANGE cr;
SynCtrl.GetSel(cr);
if( cr.cpMin == cr.cpMax )
return SynCtrl.LineFromChar( cr.cpMax );
else
return m_nCurrentLine;
}
DWORD CSynEditView::GetParseCookie(int nLineIndex)
{
CRichEditCtrl &SynCtrl=GetRichEditCtrl();
if (m_pdwParseCookies == NULL)
{
m_nParseArraySize = m_nLineCount;
m_pdwParseCookies = new DWORD[m_nLineCount];
memset(m_pdwParseCookies, 0xff, m_nLineCount * sizeof(DWORD));
}
if (nLineIndex < 0)
return 0;
if (m_pdwParseCookies[nLineIndex] != (DWORD) -1)
return m_pdwParseCookies[nLineIndex];
register int L = nLineIndex;
while (L >= 0 && m_pdwParseCookies[L] == (DWORD) -1)
L --;
L ++;
int nBlocks = 0;
CString strLine;
BOOL bRealReturn = m_bRealReturn;
while (L <= nLineIndex)
{
DWORD dwCookie = 0;
if (L > 0) {
dwCookie = m_pdwParseCookies[L - 1];
if(bRealReturn )
dwCookie &= COOKIE_EXT_COMMENT;
}
ASSERT(dwCookie != (DWORD) -1);
bRealReturn = GetLineString(L, strLine);
m_pdwParseCookies[L] = ParseLine(dwCookie, strLine, NULL, nBlocks);
ASSERT(m_pdwParseCookies[L] != (DWORD) -1);
L ++;
}
return m_pdwParseCookies[nLineIndex];
}
//取指定行文本,返回指定该行在WrapToWindow模式下是否为硬回车
//[注]在WrapToWindow模式下如果一行过长则会被分割成多行,此时只有最后一行才是硬回车
BOOL CSynEditView::GetLineString(int nLine, CString &strLine)
{
strLine = _T("");
CRichEditCtrl &SynCtrl=GetRichEditCtrl();
if(nLine > m_nLineCount - 1 || nLine < 0)
return TRUE;
int nTemp = SynCtrl.LineIndex(nLine);
nTemp = SynCtrl.LineLength(nTemp) * sizeof(WCHAR);
if(nTemp<=1) {
strLine=_T(" ");
return TRUE;
}
nTemp += 4 * sizeof(WCHAR); //尽量多留点空
int nLen = SynCtrl.GetLine(nLine, strLine.GetBuffer(nTemp), nTemp);
strLine.ReleaseBuffer();
BOOL bRealReturn;
if(nLen > strLine.GetLength())
nLen = strLine.GetLength();
if(nLen>=1 && strLine[nLen-1]==0xd ) {
strLine = strLine.Left(--nLen);
bRealReturn=TRUE;
}
else {
strLine = strLine.Left(nLen);
bRealReturn=FALSE;
}
strLine += _T(" ");
return bRealReturn;
}
//重置语法解析缓冲区
void CSynEditView::ResetParseCookie()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -