多行编辑框 CEdit
编辑框(Edit Box)控件实际上是一个简易的正文编辑器,用户可以在编辑框中输入并编辑正文。
编辑框既可以是单行的,也可以是多行的,多行编辑框是从零开始编行号的.在一个多行编辑框中,
除了最后一行外,每一行的结尾处都有一对回车换行符(用"\r\n"表示).这对回车换行符是正文换行的标志
,在屏幕上是不可见的.
编辑框控件会向父窗口发出如表6.5所示的控件通知消息.
消息
含义
EN_CHANGE
编辑框的内容被用户改变了。与EN_UPDATE不同,该消息是在编辑框显示的正文被刷新后才发出的。
EN_ERRSPACE
编辑框控件无法申请足够的动态内存来满足需要。
EN_HSCROLL
用户在水平滚动条上单击鼠标。
EN_KILLFOCUS
编辑框失去输入焦点。
EN_MAXTEXT
输入的字符超过了规定的最大字符数。在没有ES_AUTOHSCROLL或ES_AUTOVSCROLL的编辑框中,
当正文超出了编辑框的边框时也会发出该消息。
EN_SETFOCUS
编辑框获得输入焦点。
EN_UPDATE
在编辑框准备显示改变了的正文时发送该消息。
EN_VSCROLL
用户在垂直滚动条上单击鼠标。
MFC的CEdit类封装了编辑框控件。CEdit类的成员函数Create负责创建按钮控件,该函数的声明为
BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );
参数dwStyle指定了编辑框控件风格,如表6.6所示,dwStyle可以是这些风格的组合。rect指定了编辑框的位置和尺寸。
pParentWnd指定了父窗口,不能为NULL。编辑框的ID由nID指定。如果创建成功,该函数返回TRUE,否则返回FALSE.
表6.6 编辑框控件的风格
控件风格
含义
ES_AUTOHSCROLL
当用户在行尾键入一个字符时,正文将自动向右滚动10个字符,当用户按回车键时,正文总是滚向左边。
ES_AUTOVSCROLL
当用户在最后一个可见行按回车键时,正文向上滚动一页。
ES_CENTER
在多行编辑框中使正文居中。
ES_LEFT
左对齐正文。
ES_LOWERCASE
把用户输入的字母统统转换成小写字母。
ES_MULTILINE
指定一个多行编辑器。若多行编辑器不指定ES_AUTOHSCROLL风格,则会自动换行,若不指定ES_AUTOVSCROLL,
则多行编辑器会在窗口中正文装满时发出警告声响。
ES_NOHIDESEL
缺省时,当编辑框失去输入焦点后会隐藏所选的正文,当获得输入焦点时又显示出来。设置该风格可禁止这种缺省行为。
ES_OEMCONVERT
使编辑框中的正文可以在ANSI字符集和OEM字符集之间相互转换。这在编辑框中包含文件名时是很有用的。
ES_PASSWORD
使所有键入的字符都用“*”来显示。
ES_RIGHT
右对齐正文。
ES_UPPERCASE
把用户输入的字母统统转换成大写字母。
ES_READONLY
将编辑框设置成只读的。
ES_WANTRETURN
使多行编辑器接收回车键输入并换行。如果不指定该风格,按回车键会选择缺省的命令按钮,这往往会导致对话框的关闭。
除了上表中的风格外,一般还要为控件指定WS_CHILD、WS_VISIBLE、WS_TABSTOP和WS_BORDER窗口风格,WS_BORDER使控件带边框。
创建一个普通的单行编辑框应指定风格为WS_CHILD|WS_VISIBLE|WS_TABSTOP |WS_BORDER|ES_LEFT|ES_AUTOHSCROLL,这将创建一个带
边框、左对齐正文、可水平滚动的单行编辑器。要创建一个普通多行编辑框,还要附加ES_MULTILINE|ES_WANTRETURN|ES_AUTOVSCROLL
|WS_HSCROLL| WS_VSCROLL风格,这将创建一个可水平和垂直滚动的,带有水平和垂直滚动条的多行编辑器。
对于用对话框模板编辑器创建的编辑框控件,可以在控件的属性对话框中指定表6.6中列出的控件风格。例如,在属性对话框中选择Multi-line
项,相当与指定了ES_MULTILINE风格。
编辑框支持剪贴板操作。CEdit类提供了一些与剪贴板有关的成员函数,如表6.7所示。
表6.7 与剪切板有关的CEdit成员函数
函数声明
用途
void Clear( )
清除编辑框中被选择的正文。
void Copy( )
把在编辑框中选择的正文拷贝到剪贴板中。
void Cut( )
清除编辑框中被选择的正文并把这些正文拷贝到剪贴板中。
void Paste( )
将剪贴板中的正文插入到编辑框的当前插入符处。
BOOL Undo( )
撤消上一次键入。对于单行编辑框,该函数总返回TRUE,对于多行编辑框,返回TRUE表明操作成功,否则返回FALSE。
可以用下列CEdit或CWnd类的成员函数来查询编辑框。在学习下面的函数时,读者会经常遇到术语字符索引.
字符的字符索引是指从编辑框的开头字符开始的字符编号,它是从零开始编号的.也就是说,字符索引实际上是指当
把整个编辑正文看作一个字符串数组时,该字符所在的数组元素的下标.
int GetWindowText( LPTSTR lpszStringBuf, int nMaxCount ) const;
void GetWindowText( CString& rString ) const;
这两个函数均是CWnd类的成员函数,可用来获得窗口的标题或控件中的正文。
第一个版本的函数用lpszStringBuf参数指向的字符串数组作为拷贝正文的缓冲区,参数nMaxCount可以拷贝到缓冲区中的最大字符数,
该函数返回以字节为单位的实际拷贝字符数(不包括结尾的空字节)。第二个版本的函数用一个CString对象作为缓冲区。
int GetWindowTextLength( ) const;
CWnd的成员函数,可用来获得窗口的标题或控件中的正文的长度。
DWORD GetSel( ) const;
void GetSel( int& nStartChar, int& nEndChar ) const;
两个函数都是CEdit的成员函数,用来获得所选正文的位置。GetSel的第一个版本返回一个DWORD值,
其中低位字说明了被选择的正文开始处的字符索引,高位字说明了选择的正文结束处的后面一个字符的字符索引,
如果没有正文被选择,那么返回的低位和高位字节都是当前插入符所在字符的字符索引。GetSel的第二个版本的两个参数是两个引用
,其含义与第一个版本函数返回值的低位和高位字相同。
int LineFromChar( int nIndex = –1 ) const;
CEdit的成员函数,仅用于多行编辑框,用来返回指定字符索引所在行的行索引(从零开始编号)。参数nIndex指定了一个字符索引,
如果nIndex是-1,那么函数将返回选择正文的第一个字符所在行的行号,若没有正文被选择,则该函数会返回当前的插入符所在行的行号。
int LineIndex( int nLine = –1 ) const;
CEdit的成员函数,仅用于多行编辑框,用来获得指定行的开头字符的字符索引,如果指定行超过了编辑框中的最大行数,
该函数将返回-1。参数nLine是指定了从零开始的行索引,如果它的值为-1,则函数返回当前的插入符所在行的字符索引。
int GetLineCount( ) const;
CEdit的成员函数,仅用于多行编辑框,用来获得正文的行数。如果编辑框是空的,那么该函数的返回值是1。
int LineLength( int nLine = –1 ) const;
CEdit的成员函数,用于获取指定字符索引所在行的字节长度(行尾的回车和换行符不计算在内)。参数nLine说明了字符索引.
如果nLine的值为-1,则函数返回当前行的长度(假如没有正文被选择),或选择正文占据的行的字符总数减去选择正文的字符
数(假如有正文被选择)。若用于单行编辑框,则函数返回整个正文的长度。
int GetLine( int nIndex, LPTSTR lpszBuffer ) const;
int GetLine( int nIndex, LPTSTR lpszBuffer, int nMaxLength ) const;
CEdit的成员函数,仅用于多行编辑框,用来获得指定行的正文(不包括行尾的回车和换行符)。参数nIndex是行号,lpszBuffer
指向存放正文的缓冲区,nMaxLength规定了拷贝的最大字节数,若。函数返回实际拷贝的字节数,若指定的行号大于编辑框的
实际行数,则函数返回0。需要注意的是,GetLine函数不会在缓冲区中字符串的末尾加字符串结束符(NULL).
下列CWnd或CEdit类的成员函数可用来修改编辑框控件。
void SetWindowText( LPCTSTR lpszString );
CWnd的成员函数,可用来设置窗口的标题或控件中的正文。参数lpszString可以是一个CString对象,或是一个指向字符串的指针。
void SetSel( DWORD dwSelection, BOOL bNoScroll = FALSE );
void SetSel( int nStartChar, int nEndChar, BOOL bNoScroll = FALSE );
CEdit的成员函数,用来选择编辑框中的正文。参数dwSelection的低位字说明了选择开始处的字符索引,高位字说明了选择结束处
的字符索引。如果低位字为0且高位字节为-1,那么就选择所有的正文,如果低位字节为-1,则取消所有的选择.参数bNoScroll的
值如果是FALSE,则滚动插入符并使之可见,否则就不滚动.参数nStartChar和nEndChar的含义与参数dwSelection的低位字和高位字相同.
void ReplaceSel( LPCTSTR lpszNewText, BOOL bCanUndo = FALSE );
CEdit的成员函数,用来将所选正文替换成指定的正文.参数lpszNewText指向用来替换的字符串.参数bCanUndo的值为TRUE说明
替换是否可以被撤消的.
在调用上述函数时,如果涉及的是一个多行编辑框,那么除了LineLength和GetLine函数外,都要把回车和换行符考虑在内.例如,
假设在编辑框中有如下几行正文:
abcd
efg
ij
那么字母"e"的字符索引是6而不是4,因为"abcd"后面还有一对回车换行符.调用LineLength(7)会返回第二行的长度3.调用
LineIndex(2)会得到11.调用LineFromChar(8)会返回1.如果没有选择任何正文,并且插入符在字母"e"上,那么调用GetSel返回
值的低位和高位字都是6.
通过分析上述函数,我们可以总结出一些查询和设置编辑框的方法.
调用CWnd的成员函数GetWindowText和SetWindowText可以查询和设置编辑框的整个正文,在上一章的Register程序中,我们就使
用过这两个函数.
如果想对多行编辑框逐行查询,那么应该先调用GetLineCount获得总行数,然后再调用GetLine来获取每一行的正文.下面一段代
码演示了如何对多行编辑框进行逐行查询.
char buf[40];
int total=MyEdit.GetLineCount();
int i,length;
for(i=0;i
{
length=MyEdit.GetLine(i,buf,39);
buf[length]=0; //加字符串结束符
. . . . . .}
可以利用LineIndex和LineFromChar来在字符索引和字符的行列坐标之间相互转换.下列代码演示了在已知
字符索引的情况下,如何获得对应的行列坐标:
int row,column;
row=MyEdit.LineFromChar(charIndex);
column=charIndex-MyEdit.LineIndex(row);
下列代码演示了在已知字符的行列坐标的情况下,如何获得对应的字符索引:
int charIndex;
charIndex=MyEdit.LineIndex(row)+column;
不难看出字符索引与对应的行列坐标的关系是:字符索引=LineIndex(行坐标)+列坐标.
对于选择正文的查询和设置,应该利用函数GetSel、SetSel和ReplaceSel.
可以利用GetSel和SetSel来查询和设置插入符的位置.SetSel可以使编辑框滚动到插入符的新位置.
要获取插入符的行列坐标,可用下面的代码实现:
MyEdit.SetSel(-1,0); //取消正文的选择
int start,end,row,column;
MyEdit.GetSel(start,end); //start或end的值就是插入符的字符索引
row=MyEdit.LineFromChar(start); //获取插入符的行坐标
column=start-MyEdit.LineIndex(row); //获取插入符的列坐标
下面的代码演示了如何把插入符移到指定的行和列:
MyEdit.SetSel(-1,0); //取消正文的选择
int charIndex=MyEdit.LineIndex(row)+column;
MyEdit.SetSel(charIndex,charIndex);
可以利用ReplaceSel函数在 插入符处插入正文,典型的代码如下所示:
MyEdit.SetSel(-1,0); //取消正文的选择
MyEdit.ReplaceSel(“......”);
可以利用ReplaceSel清除编辑框中的正文,典型的代码如下所示:
MyEdit.SetSel(0,-1); //选择全部正文
MyEdit.ReplaceSel(“”);