|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionControls within a control with a cool example – “Do remember, controls are nothing but child windows. They can get all messages that a window can get.” This article will go along with a RichEdit control example. In the example, a rich edit control is subclassed and a list box is used as a child control, i.e., a ListBox within a RichEdit control. Subclassing a control:Subclassing a control is nothing but having your own class derived from an existing control class (like Example Details:In our example, I used some string parsing functions inside the class. I am not sure that they are all well defined. May be they are. But, as the core is different let us keep it as a second thing. Why RichEditCtrl?No special reasons. I have done a sample Editor project using Detecting a drive letterWhile typing in the edit control, we have to check whether any drive letter is typed or not in the format “driveletter:\”, if yes, then create a list box, show it with a list of available directories and files in that path, or if it is not a valid path/drive letter then do nothing. To do so, add void CMyRichEditCtrl::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) { CString str; GetWindowText(str); // get rich control text long sl,el; GetSel(sl,el); long rpos=str.Find("\r\n",0); if(sl>rpos && rpos!=-1) SetSel(rpos,rpos); if(str.Mid(sl-1,1)=="\\" && nChar!=VK_ESCAPE && nChar!=VK_BACK) { long spos=ReverseFind(str,":",sl); // Find a : in back long bpos=ReverseFind(str,"\r\n",sl); if(spos!=-1 && spos>bpos) { long pos=ReverseFind(str," ",spos); // Find a space in back if(pos==-1 || pos<bpos) pos=bpos; CString path=str.Mid(spos-2,sl-(spos-2)); if(path.Find(":\\",0)!=-1) // if drive letter { ShowDirList(path); // show directory list } } } CRichEditCtrl::OnKeyUp(nChar, nRepCnt, nFlags); } Creating a control inside a control:void CMyRichEditCtrl::ShowDirList(CString sDir) { CPoint point=GetCaretPos(); // To position the list control if(!m_dirlist) // Check whether already created or not { m_dirlist= new CListBox(); m_dirlist->Create(WS_CHILD|WS_THICKFRAME| WS_VISIBLE|WS_HSCROLL| WS_VSCROLL|LBS_SORT| WS_BORDER|LBS_STANDARD, CRect(CPoint(point.x+5,point.y), CPoint(point.x+200,point.y+100)),this,1000); } else m_dirlist->SetWindowPos(&wndTop,point.x+5,point.y, 200,100,SWP_SHOWWINDOW); m_dirlist->ShowWindow(SW_SHOW); m_dirlist->SetFocus(); m_dirlist->ResetContent(); m_dirlist->Dir(DDL_READWRITE|DDL_DIRECTORY, _T(sDir+"*.*")); if(m_dirlist->GetCount()==0) m_dirlist->ShowWindow(SW_HIDE); else m_dirlist->SetCurSel(0); } The following code will create a child control inside the rich edit control: m_dirlist= new CListBox(); m_dirlist->Create(WS_CHILD|WS_THICKFRAME|....................); If we want to customize the listbox, subclass the To make a list box to list the directories and files in a specified path: m_dirlist->Dir(DDL_READWRITE|DDL_DIRECTORY, _T(sDir+"*.*")); Subclassing Example:
The above dialog will be shown if you click the ShowDlg button in the example. This dialog is just repainted with colors and is used to pick a color from 256 colors in it. This dialog is customized and used in a project of mine. The following code is the 256 color generator: COLORREF CColorDlg256::GetRGBColor(int nColor256) { switch(nColor256) { case 0:return RGB(255,0,0); //black case 1:return RGB(255,0,0); //Red case 2:return RGB(255,255,0); //Yellow case 3:return RGB(0,255,0); //Green case 4:return RGB(0,255,255); //Cyan case 5:return RGB(0,0,255); //Blue case 6:return RGB(255,0,255); //Pink case 7:return RGB(255,255,255); //White case 8:return RGB(125,125,125); //Dark Gray case 9:return RGB(192,192,192); //Light Gray case 250:return RGB(85,85,85); // Dark Gray case 251:return RGB(125,125,125); case 252:return RGB(155,155,155); case 253:return RGB(192,192,192); case 254:return RGB(220,220,220); case 255:return RGB(255,255,255); // White } int red=240,green=0,blue=0; // Start with red for(int i=10;i<250;i++) { if(i==nColor256) return RGB(red,green,blue); if(red==240 && green<240 && blue==0 ) // Green incrementaion towards Yellow green+=6; else if(red>0 && green==240 && blue==0) // Red decrementation towards Green red-=6; else if(red==0 && green==240 && blue<240) // Blue incrementation towards Cyan blue+=6; else if(red==0 && green>0 && blue==240) // Green decrementation towards Blue green-=6; else if(red<240 && green==0 && blue==240) // Red incrementation towards Pink red+=6; else if(red==240 && green==0 && blue>0) // Blue decrementation towards Red blue-=6; } return RGB(0,0,0); // Return Black } Everything is drawn... the color rects, frame like borders, frame captions. All are drawn in the BOOL CColorDlg256::OnEraseBkgnd(CDC* pDC)
{
CRect rect;
GetClientRect(rect);
CBrush bkbr;bkbr.CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
pDC->FillRect(rect,&bkbr);
CRect sqrRect(rect.left+8,rect.top+10,0,0);
CFont font;font.CreateFont(13,0,0,0,0,0,0,0,0,0,0,0,0,"small font");
pDC->SelectObject(&font);
for(int i=1;i<=255;i++)
{
CRect frect(rect.left+20,rect.top+20,rect.left+30,rect.top+30);
COLORREF rgb=GetRGBColor(i);
CBrush br;br.CreateSolidBrush(rgb);
CRect border(frect.left-1,frect.top-1,frect.right+1,frect.bottom+1);
CPen pen;
if(rgb==m_cSelectedColor)
{
pen.CreatePen(PS_DOT,3,RGB(0,0,0));
pDC->SelectObject(&pen);
}
else
{
pen.CreatePen(0,0,RGB(0,0,0));
pDC->SelectObject(&pen);
}
pDC->Rectangle(border);
pDC->FillRect(frect,&br);
rect.left+=13;
if(i==249)
{
sqrRect.right= frect.right+10;
sqrRect.bottom =frect.bottom+10;
CBrush *brush=CBrush::FromHandle((HBRUSH)GetStockObject(HOLLOW_BRUSH));
pDC->SelectObject(brush);
pDC->Rectangle(sqrRect);
pDC->SetBkColor(GetSysColor(COLOR_BTNFACE));
CString ts ="Pallette";
pDC->TextOut(sqrRect.left+10,sqrRect.top-7,ts);
GetClientRect(rect);
rect.left=(9*20)+55;
sqrRect=CRect(rect.left+8,rect.top+10,0,0);
}
else if(i==255)
{
sqrRect.right= frect.right+10;
sqrRect.bottom =frect.bottom+5;
CBrush *brush=CBrush::FromHandle((HBRUSH)GetStockObject(HOLLOW_BRUSH));
pDC->SelectObject(brush);
pDC->Rectangle(sqrRect);
pDC->SetBkColor(GetSysColor(COLOR_BTNFACE));
CString ts ="Gray Scale";
pDC->TextOut(sqrRect.left+10,sqrRect.top-7,ts);
}
else if(i==9)
{
sqrRect.right= frect.right+10;
sqrRect.bottom =frect.bottom+5;
CBrush *brush=CBrush::FromHandle((HBRUSH)GetStockObject(HOLLOW_BRUSH));
pDC->SelectObject(brush);
pDC->Rectangle(sqrRect);
pDC->SetBkColor(GetSysColor(COLOR_BTNFACE));
CString ts ="Basic Colors";
pDC->TextOut(sqrRect.left+10,sqrRect.top-7,ts);
rect.top+=35;
rect.left=0;
sqrRect.top=frect.bottom+15;
}
else if((i-9)%24==0 && i>9)
{
rect.top+=13;
rect.left=0;
}
}
return 1;
//return CDialog::OnEraseBkgnd(pDC);
}
Hence subclassing is nothing but extending the functionality of a class, that is what we are calling as Inheritance. CRichEditCtrl --------Subclassed -----> CMyRichEditCtrl
CDialog --------Subclassed -----> CColorDlg_256
And every control can have its own child control and can get all the messages that we are getting for a parent window. ConclusionThis article may not be that much detailed. None of the articles can satisfy one's expectations. But, each article should be a seed for your technical growth. Thus, I believe that this would be a seed. Thank you all.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||