原文:
http://221.199.150.103/jsj/Html/vc/wen/vcwen10.htm
用VC++6.0編程的時候,文本編輯控件Edit Box是一個經常用到的控件。如果你是用它輸入一些簡單的文字、數字等信息,直接拿來用就可以了,但如果你用它制作大文本的編輯軟件,就會覺得不好控制,許多功能無法實現,即便用CEditView,也只會生成一個類似于記事本的東西,再想加入些自己編寫的功能也很困難。下面我以CEdit為基類定義了一個CEditBox類,加入了許多文本編輯時經常要用到的接口函數,用它來控制Edit Box控件就很容易制作出具有較強文本編輯功能的編輯軟件了。
在這個擴展類中主要增加了以下功能:
①增加控件的容量,使它能容納大文本;
②可設置編輯控件文字顏色、背景色和字體;
③對控件內的文本和選擇文本的訪問;
④直接裝入文件到控件和保存控件內容到文件;
⑤自定義的右鍵菜單;
⑥多重ReDo/UnDo功能。
這些功能基本上都是獨立的,實際使用時可根據需要選用所需功能。
準備工作:用ClassWizard在工程中加入一個新類,基類選為CEdit,類名設置為CEditBox。
一、設置控件的容量:
EditBox控件默認情況下只能裝入64K的文本,如果超出,多出部分會被自動截掉。利用CEdit類的SetLimitText()函數可重新設置控件容量。
函數原型為:
void SetLimitText(UINT nMax);
參數為nMax為控件可接收的文本最大字節數。
設置方法:用ClassWizard在CEditBox類中添加消息函數PreSubclassWindow(),把設置文本容量的語句放在里面即可。
void CEditBox::PreSubclassWindow()
{
SetLimitText( -1 ); //設置編輯控件可接收的最大字節數
CEdit::PreSubclassWindow();
}
|
因為nMax為無符號整型,-1是把它設置為可以取到的最大值。你也可以根據需要設置控件的容量。
注意:在不同操作系統下,控件可設置的最大容量也不同。如果是Windows98,這個值就是64K,無法再增大了,而在Windows2000和WindowsXP下這個值要大得多,才可以起到增加控件容量的目的。
二、設置編輯控件的前景色、背景色和字體:
在CEditBox的頭文件中加入以下變量定義:
COLORREF m_ForeColor; //文本顏色
COLORREF m_BackColor; //背景色
CBrush m_BkBrush; //背景刷
CFont* p_Font; //字體指針
int m_FontSize; //字體大小(1/10點)
CString m_FontName; //字體名
|
在CEditBox的構造函數中設置它們的初值:
CEditBox::CEditBox()
{
m_ForeColor = RGB(0,0,0); //文字顏色(黑)
m_BackColor = RGB(255,255,255); //文字背景色(白)
m_BkBrush.CreateSolidBrush(m_BackColor); //背景刷
p_Font = NULL; //字體指針
}
|
在CEditBox的析構函數中回收創建的字體資源:
CEditBox::~CEditBox()
{
if( p_Font )
delete p_Font; //回收字體資源
}
|
這里只設置了前景色和背景色的默認值,如果想設置默認字體,可在上面的PreSubclassWindow()函數中進行設置:
void CEditBox::PreSubclassWindow()
{
SetLimitText( -1 ); //設置編輯控件可接收的最大字節數
m_FontSize = 100;
m_FontName = _T("宋體");
p_Font = new CFont; //生成字體對象
p_Font->CreatePointFont( m_FontSize, m_FontName ); //創建字體
SetFont( p_Font ); //設置控件默認字體
CEdit::PreSubclassWindow();
}
|
這里使用了比較簡單的CreatePointFont()函數創建字體,它只需給出字體尺寸和字體名。如果想創建更復雜的字體,可以改用CreateFont()函數。本例中設置控件的初始字體為尺寸為100(0.1點)的“宋體”字。
如果你想用EditBox本身的默認字體作為初始字體,就不要在PreSubclassWindow()函數中加入這些語句。
用ClassWizard添加消息反射函數CtlColor()來修改控件的文本顏色和背景色。
注意:在ClassWizard下可看到有兩個很相似的消息,一個是“=WM_CTLCOLOR”消息,另一個是“WM_CTLCOLOR”消息,這里必須用“=WM_CTLCOLOR”消息添加函數。如果誤用了“WM_CTLCOLOR”消息將得不到想要的效果。
HBRUSH CEditBox::CtlColor(CDC* pDC, UINT nCtlColor)
{
pDC->SetTextColor( m_ForeColor ); //設置控件文字顏色
pDC->SetBkColor( m_BackColor ); //設置文字的背景色
return (HBRUSH)m_BkBrush.GetSafeHandle(); //控件背景刷
}
|
PreSubclassWindow()和CtlColor()函數都是消息函數,為了設置控件顏色和字體,還需定義接口函數在使用時調用:
//設置文本顏色
void CEditBox::SetForeColor(COLORREF color)
{
m_ForeColor = color;
Invalidate();
}
//獲取文本顏色
COLORREF CEditBox::GetForeColor()
{
return m_ForeColor;
}
//設置背景顏色
void CEditBox::SetBkColor(COLORREF color)
{
m_BackColor = color;
m_BkBrush.Detach();
m_BkBrush.CreateSolidBrush( m_BackColor );
Invalidate();
}
//獲取背景色
COLORREF CEditBox::GetBkColor()
{
return m_BackColor;
}
//設置字體
void CEditBox::SetTextFont(int FontSize,LPCTSTR FontName)
{
if ( p_Font ) delete p_Font;
p_Font = new CFont;
p_Font->CreatePointFont( FontSize, FontName );
SetFont( p_Font );
m_FontSize = FontSize;
m_FontName = FontName;
}
//獲取字體大小
int CEditBox::GetFontSize()
{
return m_FontSize;
}
//獲取字體名
CString CEditBox::GetFontName()
{
return m_FontName;
}
|
至此,用CEditBox類可以定義出可設置顏色和字體的Edit Box控件了。使用時,先在對話框中加入一個Edit Box控件,用ClassWizard為定義一個控制變量m_Edit,類型設定為CEditBox。然后用m_Edit.SetForeColor(color)、m_Edit.SetBkColor()和m_Edit.SetTextFont(FontHight,FontName)為控件設置顏色和字體,這樣就可以作出一個美觀的文本框了。
說明:Edit Box控件只能放入純文本,不支持對文本格式的設置,也就不能對局部的文字顏色和字體進行設置,所以,以上設置都是針對整個控件的。
三、訪問編輯控件的內容:
Edit Box控件已經提供了幾種訪問控件內容的方法:
①定義一個與控件關聯的變量,類型可設置為CString或其它類型,用UpdateData()函數來更新控件或變量。
②用GetWindowText()獲取控件內文本,用SetWindowText()設置控件文本。
③用SetSel()設置控件內的選擇區,用GetSel()獲取控件中選擇文本的位置,用ReplaceSel()替換選擇的文本。
但只用這幾種方法還是不太方便,所以在CEditBox類中又增加了幾個訪問接口函數。
1、讀取控件文本ReadText()
int CEditBox::ReadText(CString& str)
{
GetWindowText( str ); //獲取控件文本
return str.GetLength(); //文本長度
}
|
參數str是字符串的引用,用于接收讀取的控件內容,返回值是控件中文本字節數。
2、用字符串設置控件內容SetText()
void CEditBox::SetText(LPCTSTR str)
{
SetSel( 0, -1, true ); //全選
ReplaceSel( str ); //替換
SetSel(0); //設置插入點為起始位置
}
|
參數str是準備設置控件的內容,要求是字符串。
3、讀取當前選擇的文本ReadSelText()
int CEditBox::ReadSelText(CString& str)
{
int selStart, selEnd;
GetSel( selStart, selEnd ); //獲取當前選擇的位置
int selLen = selEnd-selStart; //求選擇區長度
if( selLen )
{
CString text;
GetWindowText( text ); //獲取控件文本
str = text.Mid( selStart, selLen ); //獲取選擇的文本
}
else
str = _T("");
return selLen;
}
|
參數str是字符串的引用,用于接收讀出的文本,返回值是讀出的文本字節數。
如果當前控件中有內容被選擇,則讀出選擇文本,并返回長度;如果沒有選擇的文本,讀出的是空串,返回為0。
4、設置選擇區SetSelText()
void CEditBox::SetSelText(int nStartChar,int nSelLen)
{
SetSel(nStartChar,nStartChar+nSelLen);
}
|
參數nStartChar為選擇區起點(從0算起),nSelLen為選擇區長度。
功能是把控件的指定區域設置為選擇的狀態。
5、當前是否有選擇isSelect()
BOOL CEditBox::isSelect()
{
int selStart, selEnd;
GetSel( selStart, selEnd ); //獲取當前選擇的位置
return selEnd-selStart;
}
|
如果當前控件中有選擇的文本,返回非0值,否則返回0。
以上是為了使控件訪問更方便而增加的接口函數。再配合CEdit本身提供的訪問函數,很多操作都可輕易實現了。
CEdit控件提供訪問函數主要有:
int GetWindowText(LPCTSTR lpszStringBuf,int nMaxCount);
獲取控件文本,與ReadText()功能相同。
void SetWindowText(LPCTSTR lpszString);
設置控件文本。
void GetSel(int& nStartChar,int& nEndChar);
獲取選擇區的位置
void SetSel(int nStartChar,int nEndChar,BOOL bNoScroll=FALSE);
設置選擇區,參數為起點和終點,用SetSel(0,-1)可設置為全選
void ReplaceSel(LPCTSTR lpszNewText,BOOL bCanUndo=FALSE);
用字符串替換選擇的文本
四、與文件的接口:
這部分接口函數供“打開文件”和“保存文件”等操作調用。把它們定義在CEditBox類中,增強了控件的封裝性,也可以簡化應用中“打開”和“保存”的操作。
1、文件內容裝入Edit控件
void CEditBox::LoadFile(LPCTSTR PathName)
{
CFile file; //構造一個CFile類的對象
if( file.Open( PathName, CFile::modeRead )==0 ) //以讀方式打開文件
return;
int len = file.GetLength(); //求文件長度
CString text = _T("");
file.Read( text.GetBufferSetLength(len), len ); //讀文件
text.ReleaseBuffer();
file.Close(); //關閉文件
SetText( text ); //裝入編輯控件
m_PathName = PathName;
SetModify( false ); //清除修改標志
}
|
參數PathName為文件路徑名,調用該函數可以把指定文件裝入編輯控件。如果文件不存在,直接返回。
2、保存編輯控件內容到文件
void CEditBox::SaveFile(LPCTSTR PathName)
{
CFile file;
if( file.Open( PathName, CFile::modeCreate | CFile::modeWrite )==0 )
return;
CString text;
int textLen = ReadText( text );
file.Write( (LPCTSTR)text, textLen ); //把字符串內容寫入文件
file.Close(); //關閉文件
m_PathName = PathName;
SetModify( false ); //清除修改標志
}
|
參數PathName為文件路徑名,調用該函數可以把控件內容寫入指定文件。如果建立文件失敗,直接返回。
3、新建文件
void CEditBox::NewFile()
{
SetSel( 0, -1, true ); //全選
Clear(); //清除
m_PathName = _T("");
SetModify( false ); //清除修改標志
}
|
供“新建”文件菜單消息調用,功能是清空控件。
4、是否有文件打開
BOOL CEditBox::isOpenFile()
{
return !(m_PathName.IsEmpty());
}
|
如果控件中已經有打開的文件,返回非0,否則返回0。
5、獲取打開的文件名
CString CEditBox::GetPathName()
{
return m_PathName;
}
|
如果控件中已經有打開的文件,返回文件路徑名,否則返回空串。
這5個函數中的m_PathName是在CEditBox中定義的字符串變量,并初始化為空串。
五、自定義右鍵菜單:
文本編輯框已經提供了一個默認右鍵菜單,如果你想重新定義一個來代替它,可以按下面的方法制作。
在VC++的Project菜單下選擇Add To Project下的Components and Controls,在彈出的對話框中打開Visual C++ Components,找到Pop-up Menu,單擊Insert按鈕,選擇加入的類為CEditBox,確定。關閉對話框。
這時,你在CEditBox類中會看到已經加入了下面的代碼:
void CEditBox::OnContextMenu(CWnd*, CPoint point)
{
// CG: This block was added by the Pop-up Menu component
{
if (point.x == -1 && point.y == -1){
//keystroke invocation
CRect rect;
GetClientRect(rect);
ClientToScreen(rect);
point = rect.TopLeft();
point.Offset(5, 5);
}
CMenu menu;
VERIFY(menu.LoadMenu(CG_IDR_POPUP_EDIT_BOX));
CMenu* pPopup = menu.GetSubMenu(0);
ASSERT(pPopup != NULL);
CWnd* pWndPopupOwner = this;
while (pWndPopupOwner->GetStyle() & WS_CHILD)
pWndPopupOwner = pWndPopupOwner->GetParent();
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,
pWndPopupOwner);
}
}
|
再到資源的Menu下,你可以找到一個ID號為CG_IDR_POPUP_EDIT_BOX的新菜單,編輯它就可得到你想要的右鍵菜單了。這和其它菜單的做法沒有區別,我就不再詳細介紹了。