1、WINCE6下自绘EDITWINCE6.0中自画EDITSUNNY.MAN本人在此郑重声明,写这个EDIT绝不是为了好看或是哗众取宠。我的ARM主频是400M的,当我一次性放了超过30个EDIT时,显示这个对话框时,刷新时居然是一行行的刷出来的EDIT。所以自己在对话框的界面上,自已画了这个EDIT,其实只是在对话框上完成固定资产区域的输入,顺便把画的过程中容易出现的一些问题也了下来,这就是本文的由来一、EDIT外观图 图中所示的红色区域内的就是EDIT控件,这个控件其实只是对话框上的一个区域。下面我将粗略的讲一下我的开发过程。首先把这个控件命名为CCEEditBox公共继承自CCECwnd.
2、这个CCECwnd是我自定义的一个c+类,只为了以后控件的虚拟化,给所有的控件人为的制造一个父类。它不是来自CWnd类,它只是一个c+类。它的成员变量有如下几个:BOOL m_bFocus;/是否获得焦点 int m_nControlType; /控件类型 CString m_strCaption; /内容 CRect m_rect;/自己的RECT所在位置 CDialog *m_pParent; BOOL m_bInitializationed; /是否内存DC已经初始化 COLORREF m_TextColor; CFont m_TextFont;BOOL m_bVisible;二控件的定
3、义class CCEEdit :public CCECWnd2.1.成员变量private:CCEMemDC m_memDC; /内存DC,就是简单的封装了一下CDC和CBitmap的使用。 CRect m_ClientRect; BOOL m_bSetCur; BOOL m_bCareShow; int m_nCharPosition;/开始画字符位置 int m_nStartTypeCharPosition;/输入字符的位置 int m_nMaxChar; BOOL m_bOnlyNumber;2.2.成员函数2.2.1Vid DrawBoder()任何一个控件都必须完成边框的绘制,以便有
4、一个区域。我这个也不例外,当初始化完成后,将根据m_rect在父对话框的背景上画EDIT的边框。CRect rct(0,0,m_rect.Width(),m_rect.Height();m_memDC-FillSolidRect(rct,RGB(255,2555,255);m_memDC-Draw3dRect(rct,RGB(0,0,255),RGB(0,0,255); /输入字符的位置2.2.2 void DrawNewCaption() 在边框内写文字,暂时设定文字为白底蓝字,每次有新的输入、删除、字符显示的开始位置变化,都要重新输出文字内容。int nCount=0; for(int i
5、=1;iGetTextExtent(m_strCaption.Mid(m_nCharPosition,i); int nRes=m_rect.left+size.cx; if(nResm_rect.right) break; else nCount+; m_memDC-DrawText(m_strCaption.Mid(m_nCharPosition,nCount),m_ClientRect,DT_LEFT|DT_VCENTER|DT_SINGLELINE); 采用FOR主要是不能让写入的文字超出绘定的矩形框,因为场景中的文字不是等比例的字体,所以“l”和“国”是不可能等宽的。所以只能一个个的
6、字符判断,当然可以按一个中间字来估算,然后前移或后移,会提高效率,但我没有做这个优化。如果不进行这个算法,就会显示半个字符,可你会发现MS的EDIT没有这种情况。2.2.3需要处理的消息1.来自父窗口的On_Paint消息我在对话框中放了一个链表,用来记录所有加入的控件,在背景被刷新时,当循环发送给所有的控件,并带着无效区域,各控件按区域是否包含自己来判断自己是否需要重画。如下代码在控件的OnPaint里if(rect!=NULL) CRect rr; if(rr.IntersectRect(&m_rect,rect)=FALSE) return; pDes-BitBlt(m_rect.lef
7、t ,m_rect.top,m_rect.Width(),m_rect.Height(),m_memDC,0,0,SRCCOPY); if(m_bFocus)/如果焦点发生变化,则应该对光标进行处理。 if(m_bCareShow=FALSE) m_bCareShow=TRUE; if(m_pParent) m_pParent-SetEditCare(this); else if(m_bCareShow) m_bCareShow=FALSE; if(m_pParent) m_pParent-RemoveEditCare(this); 2.BOOL OnLButtonDown(UINT nFla
8、gs, CPoint point)当有左键按下时,此时应该把光标闪烁的位置,进行移动,同时如果获得焦点,应该告知父对话框,刚才有焦点那个控件,应该失去。if(nFlags=1) if(m_rect.PtInRect(point) if(m_bFocus =FALSE)/显示光标并处理位置 m_bFocus=TRUE; if(m_pParent) m_pParent-UnFocus(this); int nLeft=CalculatePosition(point); :SetCaretPos(nLeft,m_rect.top+(m_rect.Height()-14)/2); :ShowCaret
9、 (m_pParent-m_hWnd); m_bCareShow=TRUE; else/处理光标位置 if(m_bCareShow) int nLeft=CalculatePosition(point); :SetCaretPos(nLeft,m_rect.top+(m_rect.Height()-14)/2); return TRUE; /*/ return FALSE; 3.CalculatePosition(CPoint)这个函数用来计算,当前鼠标在第几个字符后面,应该在哪里闪烁。 int nRes=0; int OldRes=0; m_nStartTypeCharPosition=m_
10、nCharPosition;/ 一个为字符的输入位置,一个是显示开始位置 for(int i=0;iGetTextExtent(m_strCaption.Mid(m_nCharPosition,i); m_nStartTypeCharPosition=m_nCharPosition+i;/因为显示的不一定是第一个字符 nRes=m_rect.left+size.cx; if(nRespt.x | nResm_rect.right)/如果这个字符在鼠标后面,或是到了边框最右边 if(nRes-(nRes-OldRes)/2pt.x)/是否超过了1/2字符如果超过,就向后,如果没有向前 nRes=
11、OldRes; m_nStartTypeCharPosition-=1; if(m_nStartTypeCharPositionInvalidateRect(m_rect); OnControlClick(); return TRUE; return FALSE;5.BOOL OnMouseMove(UINT nFlags, CPoint point) 这个移动,应该分两种情况,一种是按着鼠标左键的时候,一种是没有。按着左键应该处理选择的长度问题,因为我没有选择区故这种情况没有处理。我只是做了鼠标指针的变化,也就是把箭头形状变为输入光标。if(m_rect.PtInRect(point) if
12、(m_bSetCur=FALSE) SetCursor(AfxGetApp()-LoadStandardCursor(IDC_IBEAM); m_bSetCur=TRUE; return TRUE; else if(m_bSetCur) SetCursor(AfxGetApp()-LoadStandardCursor(IDC_ARROW); m_bSetCur=FALSE; return FALSE;6.字符的输入EDIT最重要的就要是输入字符,所以处理onChar就是必不可少的,输入时要从输入光标处开始输入,同时又要判断输入的字符,因为OnChar这个消息来自对话框,所以一定要在有焦点时才处
13、理输入,这个很重要。 BOOL OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) if(m_bFocus) BOOL bAllowType=FALSE; if(m_bOnlyNumber)/只允许输入数字时,需要判断是否是0-9和小数点 if(nChar=48 & nChar=57)/48=0 57=9 bAllowType=TRUE; else if(nChar=46)/46 . if(m_strCaption.Find(nChar)=-1) bAllowType=TRUE; else if(nChar!=8)/如果是退格,不应该进行输入处理 bAl
14、lowType=TRUE; if(bAllowType & m_strCaption.GetLength()GetTextExtent(m_strCaption.Mid(m_nCharPosition,m_nStartTypeCharPosition-m_nCharPosition); if(m_rect.rightGetTextExtent(m_strCaption.Mid(m_nCharPosition,m_nStartTypeCharPosition-m_nCharPosition); :SetCaretPos(m_rect.left+1+size.cx,m_rect.top+(m_re
15、ct.Height()-14)/2); DrawNewCaption(); m_pParent-InvalidateRect(m_rect); if(nChar=8)/8 GetTextExtent(m_strCaption.Mid(m_nCharPosition); /如果字符长度原先大于矩形 if( m_nCharPosition0 & (m_rect.left+size.cx)GetTextExtent(m_strCaption.Mid(m_nCharPosition,m_nStartTypeCharPosition-m_nCharPosition); if(m_nStartTypeCh
16、arPositionInvalidateRect(m_rect); return TRUE;7. BOOL OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)KeyDown主要是处理左右键,以便移动输入的光标,并且左右显示编辑框中的内容。 if(nChar=37)/向左的键头 if(m_nStartTypeCharPosition0) m_nStartTypeCharPosition-; if(m_nCharPosition0 & m_nCharPosition=m_nStartTypeCharPosition) m_nCharPosition-;
17、 CSize size=m_memDC-GetTextExtent(m_strCaption.Mid(m_nCharPosition,m_nStartTypeCharPosition-m_nCharPosition); :SetCaretPos(m_rect.left+1+size.cx,m_rect.top+(m_rect.Height()-14)/2); DrawNewCaption(); m_pParent-InvalidateRect(m_rect); else if(nChar=39) if(m_nStartTypeCharPositionGetTextExtent(m_strCap
18、tion.Mid(m_nCharPosition,m_nStartTypeCharPosition-m_nCharPosition); if(m_rect.rightGetTextExtent(m_strCaption.Mid(m_nCharPosition,m_nStartTypeCharPosition-m_nCharPosition); :SetCaretPos(m_rect.left+1+size.cx,m_rect.top+(m_rect.Height()-14)/2); DrawNewCaption(); m_pParent-InvalidateRect(m_rect); retu
19、rn TRUE;8. 创建控件并初始化DCvoid intEditAndDC(CRect rect,CDC *pParentDC,CCEDialog *pParent,CString strCaption)这个主要用来创建控件,相当于CEdit的Create,但也稍有区别,这个的调用时需要父窗口的内存DC已经创建。当然窗口什么时候创建,或是用DISPLSYDC也可以,但我建议在对话框初始化完成时,因为这更符合MFC的习惯。 m_strCaption=strCaption;/按纽名称 m_rect=rect;/自己的RECT所在位置 m_pParent=pParent; if(m_bInitia
20、lizationed=FALSE) m_bInitializationed=TRUE; m_memDC.CreateDC(pParentDC,m_rect); CRect rct(0,0,m_rect.Width(),m_rect.Height(); m_memDC-SetBkMode(TRANSPARENT); m_memDC-SelectObject(&m_TextFont); m_memDC-SetTextColor(m_TextColor); m_ClientRect=rct; DrawNewCaption(); m_pParent-AddControl(CCECWnd *)this); as_mhy
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1