|
VC动态创建控件 2010-12-15 11:09 动态控件是指在需要时由Create()创建的控件,这与预先在对话框中放置的控件是不同的。
一、创建动态控件:
为了对照,我们先来看一下静态控件的创建。
放置静态控件时必须先建立一个容器,一般是对话框,这时我们在对话框编辑窗口中,从工具窗口中拖出所需控件放在对话框中即可,再适当修改控件ID,设置控件属性,一个静态控件就创建好了,当对话框被显示时,其上的控件也会显示。
静态控件不需要调用Create()函数来创建。
而创建动态控件有很大不同,以下以按钮为例,看一下动态控件的创建过程:
1.建立控件ID号:
ID号是控件的标识,创建控件前必须先为它设置一个ID号。
打开资源中的“String Table”,在空白行上双击鼠标,这时会弹出一个ID属性对话框,在其中的ID编辑框中输入ID,如:IDC_MYBUTTON,在Caption中输入控件标题或注解(注:Caption框不能为空,为空会导致创建失败),这里我输入的是按钮上要显示的文字--动态按钮。
2.建立控件对象:
不同种类的控件应创建不同的类对象:
·按钮控件 CButton (包括普通按钮、单选按钮和复选按钮) ·编辑控件 CEdit ·静态文本控件 CStatic ·标签控件 CTabCtrl ·旋转控件 CSpinButtonCtrl ·滑标控件 CSliderCtrl ·多信息编辑控件 CRichEditCtrl ·进度条控件 CProgressCtrl ·滚动条控件 CSrcollBar ·组合框控件 CComboBox ·列表框控件 CListBox ·图像列表控件 CImageCtrl ·树状控件 CTreeCtrl ·动画控件 CAnimateCtrl
本例中我们创建一个CButton类的普通按钮。注意不能直接定义CButton对象,如:CButton m_MyBut;这种定义只能用来给静态控件定义控制变量,不能用于动态控件。
正确做法是用new调用CButton构造函数生成一个实例:
CButton *p_MyBut = new CButton(); |
然后用CButton类的Create()函数创建,该函数原型如下: BOOL Create( LPCTSTR lpszCaption, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID ); |
lpszCaption是按钮上显示的文本;dwStyle指定按钮风格,可以是按钮风格与窗口风格的组合,取值有: 窗口风格: ·WS_CHILD 子窗口,必须有 ·WS_VISIBLE 窗口可见,一般都有 ·WS_DISABLED 禁用窗口,创建初始状态为灰色不可用的按钮时使用 ·WS_TABSTOP 可用Tab键选择 ·WS_GROUP 成组,用于成组的单选按钮中的第一个按钮 按钮风格: ·BS_PUSHBUTTON 下压式按钮,也即普通按钮 ·BS_AUTORADIOBUTTON 含自动选中状态的单选按钮 ·BS_RADIOBUTTON 单选按钮,不常用 ·BS_AUTOCHECKBOX 含自动选中状态的复选按钮 ·BS_CHECKBOX 复选按钮,不常用 ·BS_AUTO3STATE 含自动选中状态的三态复选按钮 ·BS_3STATE 三态复选按钮,不常用 以上风格指定了创建的按钮类型,不能同时使用,但必须有其一。 ·BS_BITMAP 按钮上将显示位图 ·BS_DEFPUSHBUTTON 设置为默认按钮,只用于下压式按钮,一个对话框中只能指定一个默认按钮 ·rect指定按钮的大小和位置; ·pParentWnd指示拥有按钮的父窗口,不能为NULL; ·nID指定与按钮关联的ID号,用上一步创建的ID号。 不同控件类的Create()函数略有不同,可参考相关资料。 例:p_MyBut->Create( "动态按钮", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, CRect(20,10,80,40), this, IDC_MYBUTTON ); 这样,我们就在当前对话框中的(20,10)处创建了宽60,高30,按钮文字为“动态按钮”的下压式按钮。 为了使创建过程更方便易用,我定义了如下函数: CButton* CTextEditorView::NewMyButton(int nID,CRect rect,int nStyle) { CString m_Caption; m_Caption.LoadString( nID ); //取按钮标题 CButton *p_Button = new CButton(); ASSERT_VALID(p_Button); p_Button->Create( m_Caption, WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | nStyle, rect, this, nID ); //创建按钮 return p_Button; } |
其中m_Caption.LoadString( nID )是从字符串表中读取按钮文本,这样在创建按钮ID时,应该把文本设置好,参数nStyle为除必须风格外的额外风格。 以下,调用该函数在ONINIATIAL中创建三个按钮,并指定第一个按钮为默认按钮,按钮的ID在STRING TABLE中已预先设置好了: //CButton *p_MyBtn[3];//为了在后面释放资源,改为在类头文件中声明为 //公有变量 p_MyBtn[0]=NewMyButton(ID_MYBTN1,CRect(10,20,60,40),BS_DEFPUSHBUTTON); p_MyBtn[1]=NewMyButton(ID_MYBTN2,CRect(10,50,60,70),0); p_MyBtn[2]=NewMyButton(ID_MYBTN3,CRect(10,80,60,100),0); |
二、动态控件的响应:
动态控件的响应函数不能用ClassWizard添加,只能手动添加。仍以上面的按钮为例,我们制作按钮的单击响应函数。
1.在MESSAGE_MAP中添加响应函数:
MESSAGE_MAP表中定义了消息响应函数,其格式为:消息名(ID,函数名),当我们用ClassWizard添加函数时,会自动添加在AFX_MSG_MAP括起的区间内,如:
BEGIN_MESSAGE_MAP(CTextEditorView, CFormView) //{{AFX_MSG_MAP(CTextEditorView) ON_BN_CLICKED(IDC_ICONBUT0, OnIconbut0) //}}AFX_MSG_MAP END_MESSAGE_MAP() |
手工添加时不要添加到AFX_MSG_MAP区间内,以防ClassWizard不能正常工作,如:
BEGIN_MESSAGE_MAP(CTextEditorView, CFormView) //{{AFX_MSG_MAP(CTextEditorView) ON_BN_CLICKED(IDC_ICONBUT0, OnIconbut0) //}}AFX_MSG_MAP ON_BN_CLICKED(ID_MYBTN1, OnMybtn1) ON_BN_CLICKED(ID_MYBTN2, OnMybtn2) ON_BN_CLICKED(ID_MYBTN3, OnMybtn3) END_MESSAGE_MAP() |
其中ON_BN_CLICKED是按钮单击消息。
2.在头文件中添加函数定义:
用ClassWizard添加函数时,会在头文件的AFX_MSG区间内添加函数定义,如:
protected: //{{AFX_MSG(CTextEditorView) afx_msg void OnIconbut0(); //}}AFX_MSG DECLARE_MESSAGE_MAP() |
我们模仿这种形式,只是把函数定义添加到AFX_MSG区间外就行了:
protected: //{{AFX_MSG(CTextEditorView) afx_msg void OnIconbut0(); //}}AFX_MSG afx_msg void OnMybtn1(); afx_msg void OnMybtn2(); afx_msg void OnMybtn3(); DECLARE_MESSAGE_MAP() |
3.编写消息响应函数:
以上是把消息和函数关联起来了,具体在单击按钮后应做的工作在函数中完成:
void CTextEditorView::OnMybtn1() { MessageBox( "哈!你单击了动态按钮。" ); } void CTextEditorView::OnMybtn2() { …… } void CTextEditorView::OnMybtn3() { …… } |
除了按钮的响应函数外,你还可以用上面获得的指针访问按钮,如:
修改按钮的大小和位置:p_MyBtn[0]->MoveWindow(……);
修改按钮文本:p_MyBtn[0]->SetWindowText(……);
显示/隐藏按钮:p_MyBtn[0]->ShowWindow(……);等等。
三、回收资源:
由于动态控件对象是由new生成的,它不会被程序自动释放,所以需手工释放。在控件不再使用时可以删除它,在对话框中的析构函数中销毁(析构函数没有手动添加):
CMonthCalCtrlDlg::~CMonthCalCtrlDlg() { for(int i=0;i<3;i++) {if(p_MyBtn[i]) delete p_MyBtn[i]; p_MyBtn[0]=NULL;//若采用其他方式释放,则加上这句,否则会出错 } } |
以上就是按钮控件动态生成的方法。
|
vc 如何建动态按钮 在类的定义中,定义如下变量
那么在类的成员函数中就可以使用了如下来创建按钮。
- m_btn.Create("动态创建的按钮",BS_DEFPUSHBUTTON|WS_VISIBLE|WS_CHILD,CRect(0,0,100,100),this,123);
注,创建第二次的时候会出错。所以要用。
来释放再进行创建。 借由这个动态创建,弄清了一些MFC的构架,MFC是基于所有的类而得出的成果,一个类派生与另一个基类,从CWnd到CDialog就是一个很好的例子。CDialog派生与CWnd。 如果我要创建一个按钮,就必须用CDialog定义一个新的变量,这个变量就成了一个按钮,我就可以利用这个按钮类进行 各类操作,例如定义其的大小,风格。 皆由此可见,所有的窗口都是一个类定义来的。无论是按钮,标签,ComBox,List等等,都可以使用这个方法进行创建。 在编辑代码方面,VC与VB就有了,对于用户来说,就有了本质上的差别,VB的或许更加方便,而VC需要处理的细节太多了。
//创建按钮 CButton *m_pBt1 = new CButton(); ASSERT_VALID(m_pBt1); m_pBt1-> Create(_T("进入[A]"), WS_GROUP ¦WS_CHILD ¦WS_VISIBLE ¦BS_PUSHBUTTON, CRect(10,10,20,20), this, IDC_AUTOCUT_POSTEACH ); m_pBt1-> MoveWindow(0, 152, 100, 100); //修改风格 HWND hwnd=m_pBt1-> GetSafeHwnd(); long lStyle=GetWindowLong(hwnd,GWL_EXSTYLE); SetWindowLong(hwnd,GWL_EXSTYLE,lStyle ¦WS_EX_DLGMODALFRAME); ::SetWindowPos(hwnd,0, 12, 55, 55, 111, SWP_NOREPOSITION ¦SWP_NOACTIVATE ¦SWP_NOMOVE ¦SWP_FRAMECHANGED);
//m_pdbado->GetFieldValue(_T("AccountCreateDate"),str); m_pdbado->GetFieldValue(_T("AccountCreateDate"),coledatetime); str = coledatetime.Format("%Y-%m-%d %H:%M:%S"); if (str.size()>64) { m_strError = "超过长度"; //m_pdbado->CloseRecordset(); return false; } strcpy_s(user_info.AccountCreateDate,64,str.c_str()); 要用COleDateTime coledatetime; 读取,再格式化
BOOL C*****::StartMakeing( void ) { unsigned threadID = 0; m_start = true; m_hThread =(HANDLE) _beginthreadex(NULL, 0, MakeMontage, (LPVOID)this, 0, &threadID ); return (m_start != NULL); } unsigned __stdcall C*****::MakeMontage( LPVOID lpParameter ) { if(lpParameter) { C***** *pclient = (CDossierMontage*)lpParameter; pclient->doMake(); } return 0xdead;
OnPain() CPaintDC *pdc=&dc; CRect r; GetClientRect(&r); CBitmap *pBitmap= new CBitmap; BITMAP bm; pBitmap->LoadBitmap(IDB_BG_NEW); pBitmap->GetBitmap(&bm); CDC* pDisplayMemDC = new CDC; pDisplayMemDC->CreateCompatibleDC(pdc); pDisplayMemDC->SelectObject(pBitmap); pdc->StretchBlt(r.left,r.top+30,r.Width(),r.Height()-30,pDisplayMemDC, 0,0,bm.bmWidth,bm.bmHeight,SRCCOPY); pBitmap->DeleteObject(); ReleaseDC(pdc); ReleaseDC(pDisplayMemDC); delete pDisplayMemDC; delete pBitmap; OnCtlColor //修改窗口控件背景颜色 if (nCtlColor == CTLCOLOR_STATIC) { pDC->SetBkMode(TRANSPARENT); pDC->SetTextColor(#dedede); pDC->SetBkColor(#383838); hbr = CreateSolidBrush(#383838); } if (nCtlColor == CTLCOLOR_EDIT) { pDC->SetTextColor(#dedede); pDC->SetBkColor(#13344d); hbr = CreateSolidBrush(#13344d); } OnEraseBkgnd CRect windowRect; GetWindowRect(windowRect); ScreenToClient(windowRect); pDC->FillSolidRect(windowRect, #383838); return TRUE;
if (PathFileExists(path)) { CString tempStr; tempStr.Format("shell32.dll,OpenAs_RunDLL %s",path); int isError=(int)ShellExecute(NULL, "open", "rundll32.exe ", tempStr, "", SW_SHOW); if (isError<32) { MessageBox("相应文件打开失败","提示"); } } else { MessageBox("文件路径有误!"); }
关闭 SendMessage(WM_SYSCOMMAND, SC_CLOSE); 最小化 SendMessage(WM_SYSCOMMAND, SC_MINIMIZE); 最大化 SendMessage(WM_SYSCOMMAND, SC_MAXIMIZE); 恢复原来大小 SendMessage(WM_SYSCOMMAND, SC_RESTORE); 对话框接受拖动 PostMessage(WM_NCLBUTTONDOWN,HTCAPTION,MAKELPARAM(point.x,point.y)); B00L PostMessage(HWNDhWnd,UINTMsg,WPARAMwParam,LPARAMlParam);
hWnd:其窗口程序接收消息的窗口的句柄。可取有特定含义的两个值: HWND_BROADCAST:消息被寄送到系统的所有顶层窗口,包括无效或不可见的非自身拥有的窗口、 被覆盖的窗口和弹出式窗口。消息不被寄送到子窗口 NULL:此函数的操作和调用参数dwThread设置为当前线程的 标识符PostThreadMessage函数一样 Msg:指定被寄送的消息。 wParam:指定附加的消息特定的信息。 IParam:指定附加的消息特定的信息。 返回值:如果 函数调用成功,返回非零值:如果函数调用失败,返回值是零。若想获得更多的 错误信息,请调用GetLastError函数。
SELECT COUNT(1) AS RecordNum FROM (SELECT MonitoryPointID FROM casedatarel WHERE 1=1 AND Type = 1 GROUP BY MonitoryPointID)a
在VC中,也常常为一些图片按钮添加一些功能提示。下面讲解实现过程:该功能的实现主要是用CToolTipCtrl类。该类在VC msdn中有详细说明。 首先在对话框的头文件中加入初始化语句:public:下,加入:CToolTipCtrl m_Mytip; 然后在初始化对话框函数中加入: m_Mytip.Create(this); m_Mytip.AddTool( GetDlgItem(IDC_BUTTON), "你想要添加的提示信息" ); //IDC_BUTTON为你要添加提示信息的按钮的ID m_Mytip.SetDelayTime(200); //设置延迟 m_Mytip.SetTipTextColor( #0000ff ); //设置提示文本的颜色 m_Mytip.SetTipBkColor( #ffffff); //设置提示框的背景颜色 m_Mytip.Activate(TRUE); //设置是否启用提示
然后在类向导中添加PreTranslateMessage消息响应函数 BOOL CXXXDlg::PreTranslateMessage(MSG* pMsg) { // TODO: Add your specialized code here and/or call the base class if(pMsg->message==WM_MOUSEMOVE) m_Mytip.RelayEvent(pMsg); return CDialog::PreTranslateMessage(pMsg); } 注:如果要为多个按钮添加功能提示只需在 m_Mytip.AddTool( GetDlgItem(IDC_BUTTON), "你想要添加的提示信息" ); 的下面再加上类似语句,如 m_Mytip.AddTool( GetDlgItem(IDC_BUTTON1), "你想要添加的提示信息1" ); m_Mytip.AddTool( GetDlgItem(IDC_BUTTON2), "你想要添加的提示信息2" ); 。。。。。。。。
例子:
声明:
CToolTipCtrl m_Tip; 初始化: BOOL C***Dlg::OnInitDialog() { 省略部分。。。。。。。。。。
//按钮浮动提示 m_Tip.Create(this); m_Tip.AddTool(&m_BtnPlay,"播放"); m_Tip.SetDelayTime(100); m_Tip.Activate(TRUE); } 类视图中重写: BOOL C****Dlg::PreTranslateMessage(MSG* pMsg) { // TODO: 在此添加专用代码和/或调用基类 m_Tip.RelayEvent(pMsg); }
|