程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 在MFC中創建動態控件的生成與響應

在MFC中創建動態控件的生成與響應

編輯:關於VC++

動態控件是指在需要時由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為除必須風格外的額 外風格。

以下,我調用該函數創建三個按鈕,並指定第一個按鈕為默認按鈕,按鈕的 ID已預先設置好了:

CButton *p_MyBut[3];
p_MyBut[0] = NewMyButton( ID_MYBUT1, CRect(10,20,50,35), BS_DEFPUSHBUTTON );
p_MyBut[1] = NewMyButton( ID_MYBUT2, CRect(55,20,95,35), 0 );
p_MyBut[2] = NewMyButton( ID_MYBUT3, CRect(100,20,140,35), 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_MYBUT1, OnMybut1)
ON_BN_CLICKED(ID_MYBUT2, OnMybut2)
ON_BN_CLICKED(ID_MYBUT3, OnMybut3)
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 OnMybut1();
afx_msg void OnMybut2();
afx_msg void OnMybut3();
DECLARE_MESSAGE_MAP()

3.編寫消息響應函數:

以上是 把消息和函數關聯起來了,具體在單擊按鈕後應做的工作在函數中完成:

void CTextEditorView::OnMybut1()
{
MessageBox( "哈!你單擊了動態按鈕。 " );
}
void CTextEditorView::OnMybut2()
{
……
}
void CTextEditorView::OnMybut3()
{
……
}

除了按鈕的響應函數外,你還可以用上面獲得的指針 訪問按鈕,如:

修改按鈕的大小和位置:p_MyBut[0]->MoveWindow (……);

修改按鈕文本:p_MyBut[0]->SetWindowText (……);

顯示/隱藏按鈕:p_MyBut[0]->ShowWindow (……);等等。

三、回收資源:

由於動態控件對象是由new生成 的,它不會被程序自動釋放,所以需手工釋放。在控件不再使用時可以刪除它:

if( p_MyBut[0] )
delete p_MyBut[0];

以上就是按鈕控件動態 生成的方法。下面,再看一下單選按鈕的動態生成問題。

四、實例:單選按鈕組的動 態生成

單選按鈕也屬於CButton類,但由於單選按鈕總是成組使用的,所以它在制作 和使用上與普通按鈕有一定區別。

假設有三個單選按鈕組成一組,初始時,第一個單 選按鈕處於選中狀態。

我們先來看靜態制作方法:在對話框中放置三個單選按鈕,設 置屬性如下:

Radio1屬性:Visible、Group、Tab stop、Auto

Radio2屬性: Visible、Tab stop、Auto

Radio3屬性:Visible、Tab stop、Auto

這樣的屬 性設置就把三個單選按鈕分成了一組,它們一次只能有一個被選中,若對話框中還有其它成 組的單選按鈕,使用時也會互不干擾。但這時還沒有使第一個按鈕處於選中狀態。

接 著就用ClassWizard為這組單選按鈕添加變量,這裡只需為第一個單選按鈕添加變量即可。設 變量名為m_Radio,類型選為int型。在構造函數中ClassWizard把m_Radio的值設置為-1,我 們把它改為0,這樣在運行程序時可以看到第一個單選按鈕處於選中狀態了。

之後, 還應該用ClassWizard為三個單選按鈕添加單擊響應函數,在裡面修改m_Radio的值對應三個 單選按鈕就可以了。

以上就是通常制作單選按鈕組的辦法,現我們欲改為動態生成, 主要要解決按鈕分組和單擊控制問題。以下為制作步驟:

1.定義三個單選按鈕的ID:

打開資源中的“String Table”,在其中添加三個ID值:

第一個 :ID為IDC_MYRADIO1,Caption為單選1

第二個:ID為IDC_MYRADIO2,Caption為單選 2

第三個:ID為IDC_MYRADIO3,Caption為單選3

其中Caption為按鈕上要顯示 的文字,可根據需要設置。

2.用CButton類的Create()函數生成三個單選按鈕:

為方便起見,先定義一個函數生成單選按鈕:

CButton* CTextEditorView::NewMyRadio(int nID,CRect rect,int nStyle)
{
CString m_Caption;
m_Caption.LoadString( nID );//取按鈕標題
CButton *p_Radio = new CButton();
ASSERT_VALID(p_Radio);
p_Radio->Create( m_Caption, WS_CHILD | WS_VISIBLE | nStyle | WS_TABSTOP | BS_AUTORADIOBUTTON, rect, this, nID );//創建按鈕
return p_Radio;
}

函數LoadString()用於從 “String Table”中讀取按鈕文本,Create()函數中設定了單選按鈕必須的屬性 ,其中就包括了Visible、Tab stop、Auto屬性。

參數nID為單選按鈕ID號,rect為單 選按鈕尺寸,nStyle為除必要屬性外的其它屬性。返回值為指向新建按鈕的指針。

有 了這個函數後,創建單選按鈕組時只要依次調用該函數即可,其中單選按鈕組的第一個單選 按鈕必須指定WS_GROUP屬性。

CButton *p_MyRadio[3];
p_MyRadio[0] = NewMyRadio( IDC_MYRADIO1, CRect(15,90,60,105), WS_GROUP );
p_MyRadio[1] = NewMyRadio( IDC_MYRADIO2, CRect(15,108,60,123), 0 );
p_MyRadio[2] = NewMyRadio( IDC_MYRADIO3, CRect(15,126,60,141), 0 );

3.定義單選按鈕組的 控制變量,設置第一個單選按鈕為選中狀態:

這裡不能用ClassWizard添加變量,也 不要在DoDataExchange()中添加控制變量,因為動態控件一開始並不存在,在 DoDataExchange()中添加控制變量會造成運行錯誤。這裡我們只需在頭文件中隨意定義一個 int型變量作為控制變量即可,如:

int m_SelRadio;

在構造函數中設置其初 值為0:m_SelRadio = 0;

在上面的創建按鈕的語句中,用SetCheck()函數設置初始選 中的按鈕:

CButton *p_MyRadio[3];
p_MyRadio[0] = NewMyRadio( IDC_MYRADIO1, CRect(15,90,60,105), WS_GROUP );
p_MyRadio[1] = NewMyRadio( IDC_MYRADIO2, CRect(15,108,60,123), 0 );
p_MyRadio[2] = NewMyRadio( IDC_MYRADIO3, CRect(15,126,60,141), 0 );
p_MyRadio[m_SelRadio]->SetCheck (1);//設置第一個單選為選中狀態

在SetCheck()函數中,參數為1表示設置為選中 狀態,為0表示未選中狀態。

4.添加鼠標單擊響應函數:

鼠標單擊某單選按鈕 後,其狀態已經能自動改變,這裡我們還需修改控制變量m_SelRadio的值,以便跟蹤選中的 單選按鈕。

首先在MESSAGE_MAP中把鼠標單擊消息與響應函數聯系起來:

BEGIN_MESSAGE_MAP(CTextEditorView, CFormView)
//{{AFX_MSG_MAP (CTextEditorView)
ON_BN_CLICKED(IDC_ICONBUT0, OnIconbut0)//ClassWizard在此處 添加
//}}AFX_MSG_MAP
ON_BN_CLICKED(IDC_MYRADIO1, OnMyRadio1)//單選按鈕 1
ON_BN_CLICKED(IDC_MYRADIO2, OnMyRadio2)//單選按鈕2
ON_BN_CLICKED (IDC_MYRADIO3, OnMyRadio3)//單選按鈕3
END_MESSAGE_MAP()

然後在頭文 件的MESSAGE_MAP中定義單擊函數:

protected:
//{{AFX_MSG (CTextEditorView)
afx_msg void OnIconbut0();//ClassWizard在此處添加
//}}AFX_MSG
afx_msg void OnMyRadio1();//單選按鈕1
afx_msg void OnMyRadio2();//單選按鈕2
afx_msg void OnMyRadio3();//單選按鈕3
DECLARE_MESSAGE_MAP()

這裡注意不要把函數加在AFX_MSG區間內,以防影響 ClassWizard的使用。

定義具體的響應函數(這裡是用手工加入的,不是用 ClassWizard加入的):

//單擊單選按鈕1void CTextEditorView::OnMyRadio1()
{
m_SelRadio=0;
}

//單擊單 選按鈕2void CTextEditorView::OnMyRadio2()
{
m_SelRadio=1;
}

//單擊單選按鈕3void CTextEditorView::OnMyRadio3()
{
m_SelRadio=2;
}

5.回收資源:

在析構函數中,回收創建的單選按 鈕(也可以在不使用單選按鈕時立即回收):

CTextEditorView::~CTextEditorView()
{
int i;
for( i=0; i<3; i++)
{
 if(p_MyRadio[i])
 delete p_MyRadio[i];
}
}

以上就是動態控件的生成和響應方法,各種不同的控件做法略有不同,但思路 和步驟都是類似的,希望以上實例對你能夠有所幫助。

  1. 上一頁:
  2. 下一頁:
欄目導航
Copyright © 程式師世界 All Rights Reserved