程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> VC++ >> 『VC++技術內幕』學習筆記(9)

『VC++技術內幕』學習筆記(9)

編輯:VC++

 

第九篇:模式對話框和通用控件(上)

  對話框是一個真正的窗口,它不但可以接受消息,而且可以被移動和關閉,還可以在它的客戶區中進行繪圖操作。對話框可以分為模式對話框和無模式對話框兩種,兩者區別是在對話框被關閉之前用戶能否在同一應用程序的其他地方進行工作。舉例說明:打開文件對話框便是典型的模式對話框,在你選擇好要打開的文件按下確定後,或者取消打開文件操作後,才可以在同一應用程序進行其他操作。而常見的查找和替換對話框便是無模式對話框的典型,在該對話框打開的同時,我們還可以進行其他工作。

  對話框屬於一種資源,VC的資源編輯器可以幫助我們創建和編輯對話框,這個對話框編輯器有點類似VB的編輯器界面了,大多數的常用控件都在控件工具條中列出,我們可以很容易的畫出對話框的外觀樣子,不用象SDK時控件也全部由代碼創建。書上給出了建立模式對話框的步驟,希望大家記住它。

1、用對話框編輯器創建包含各種資源和控件的對話框資源。對話框編輯器會自動更新項目的資源文件。

2、利用Class Wizard來創建CDialog的派生類,並將它和第一步創建的資源相連接。Class Wizard會再項目中自動加入相應的代碼和頭文件。

3、利用Class Wizard向對話框類中加入數據成員、交換函數和確認函數。

4、利用Class Wizard對對話框中的按鈕和其它可以產生事件的控件加入相應的消息控制函數。

5、對一些特殊的控件初始化函數(如OnInitDialog)及消息控制函數進行編輯。當用戶關閉對話框時,別忘了調用CDialog的虛成員函數OnOK。OnOK是以默認方式調用的。

6、對視圖類代碼進行編輯,以便對話框被激活。在所編寫的代碼中首先應該包含對對話框類構造函數的調用,然後再調用DoModel對話框類成員函數,只有當用戶退出對話框時,DoModel才返回。

  書上還舉了一個例子,這個例子包含了各種類型的控件,不過好象有一處錯誤(在LANG組合框處)。不過大家最好照書上的步驟完成這個例子,它對於掌握控件和對話框很有幫助,雷神在這裡不准備用書上的例子,而是自己寫一個有點意思的小程序--“體育彩票選號器” 。

程序的目的:

  我經常購買北京的體育彩票,雖然沒有中過超過50元的獎,可還是興趣盎然,只當作是支持體育事業了。我從不費神進行一些概率分析之類的工作,一般都是機選,為了演示對話框的操作,寫一個程序實現北京電腦體育彩票36選7的機選功能。

程序運行效果是:

當按下選號鍵後,由計算機隨機選出7個0-36的號碼,並顯示在對話框中的7個EDIT控件中。

設計思路:

1、為了簡單選擇"Dialog Base",省去了上面說的第6步。

2、隨機數的產生,這是游戲編程的關鍵,雷神不用細說大家也都明白。用VC產生隨機數有兩個函數,一個是Rand一個是Srand,我的用法是這樣的,先調用srand函數,如srand( (unsigned)time( NULL ) ),這樣可以每次產生的隨機數序列不同。因為各種編程語言返回的隨機數(確切地說是偽隨機數)實際上都是根據遞推公式計算的一組數值,當序列足夠長,這組數值近似滿足均勻分布。如果計算偽隨機序列的初始數值(稱為種子)相同,則計算出來的偽隨機序列就是完全相同的(這便是為什麼單獨使用Rand產生的隨機數是一樣的原因)。這個特性被有的軟件利用於加密和解密。加密時,可以用某個種子數生成一個偽隨機序列並對數據進行處理;解密時,再利用種子數生成一個偽隨機序列並對加密數據進行還原。這樣,對於不知道種子數的人要想解密就需要多費些事了。當然,這種完全相同的序列對於你來說是非常糟糕的。要解決這個問題,需要在每次產生隨機序列前,先指定不同的種子,這樣計算出來的隨機序列就不會完全相同了。你可以在調用rand()函數之前調用srand( (unsigned)time( NULL )),這樣以time函數值(即當前時間)作為種子數,因為兩次調用rand函數的時間通常是不同的,這樣就可以保證隨機性了。你也可以使用srand函 數來人為指定種子數。Windows 9x/NT的 游 戲FreeCell就允許用戶指定種子數,這樣用戶如果一次游戲沒有成功,下次還可以以同樣的發牌結果再玩一次。

3、獲得1-36號碼的算法:因為我們通過隨機函數獲得的隨機數是一個unsigned int,我們需要進行處理才能得到我們想要的數,在本例是1-36,我的算法是用得到的隨機數除36取余再加1,則得到的肯定是1-36范圍內的整數。

4、不重復:彩票中的7個數是互不相同的數字,因此還需要加一個判斷,新得到的隨機數是否有效。

5、排序:得到7個號碼後需要對它們按大小排序,這裡用的是一種常見的排序法,比較相臨的兩個數,如果後面的元素大於前面的,就交換位置。

好了,讓我們開始吧。

1)新建一個“MFC AppWizard(EXE)”程序GUESS,在選擇模式時,選擇基於“Dialog”模式,其它選項缺省;

2)將新建的對話框上缺省的控件全部刪去(一個OK按鈕,一個CANCEL按鈕),然後添加一個靜態文本控件、7個Edit控件和1個Button控件,右擊Button控件選擇Properties選項,將Caption屬性設為“選號”,同樣方法將靜態文本控件的Caption屬性設定為“電腦體育彩票選號:”;

3)右擊任一Edit控件,在出現的菜單中選擇“ClassWizard”;在“ClassWizard”中為7個Edit控件一一綁定Int型的變量如下:

Control Ids Type Member
IDC_BUTTON1
IDC_EDIT1 int m_num1
IDC_EDIT2 int m_num2
IDC_EDIT3 int m_num3
IDC_EDIT4 int m_num4
IDC_EDIT5 int m_num5
IDC_EDIT6 int m_num6
IDC_EDIT7 int m_num7


4)在“ClassWizard”中為Button控件添加一個處理過程,選擇“Message Maps”選項卡,確定Object IDs是IDC_BUTTON1,雙擊Messages中的BN_CLICKED,則“ClassWizard”會自動添加一個OnButton1() 函數。

5)編輯CGuessDlg::OnButton1() ,添加以下代碼

void CGuessDlg::OnButton1()
{
int temp,pnum[35],num[7]; //臨時變量,臨時數組
for(int i=0;i<35;i++) //共有36個數組元素
pnum[i]=i+1;
//***選號***//
for(i=0;i<7;i++)
{
srand( (unsigned)time( NULL ) );
temp=rand();
temp=temp%36+1; //得到一個1-36的數
while(pnum[temp]==0)//如果此元素以被選過則重選
{
srand( (unsigned)time( NULL ) );
temp=rand();
temp=temp%36+1;
}
num[i]=temp; //選定一個號碼
pnum[temp]=0; //給該元素置0,表示已被選過,如再有視為無效。
}
//***排序***//
for(int chance=1;chance<7;chance++)
{
int position=chance; //元素排序用到的游標
for(i=0;i<7;i++){
if(num[position]>num[i]) //如果後面的元素大於前面的,就交換位置
{
temp=num[position];
num[position]=num[i];
num[i]=temp;
}
}
}
//***顯示***//
m_num1=num[0];
m_num2=num[1];
m_num3=num[2];
m_num4=num[3];
m_num5=num[4];
m_num6=num[5];
m_num7=num[6];
UpdateData(FALSE); //通過變量刷新Edit控件的顯示
}
//********************************************************************************
/*說明:CWnd::UpdateData()
UpdateData()的原型如下:
BOOL UpdateData( BOOL bSaveAndValidate = TRUE );


UpdateData()是這樣工作的,如果調用UpdateData時傳給它的參數是FLASE,那麼通過DoDataExchange、DDX_(交換)和DDV_(確認)函數會將數據成員中的值傳遞給對話框中的控件;反之,如果調用UpdateData時傳給它的參數是TRUE,那麼通過函數會將對話框的控件傳遞給數據成員。

本例中DoDataExchange函數在CGuessDlg類中被重載,在代碼中是下面這樣的:

void CGuessDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CGuessDlg)
DDX_Text(pDX, IDC_EDIT1, m_num1);
DDX_Text(pDX, IDC_EDIT2, m_num2);
DDX_Text(pDX, IDC_EDIT3, m_num3);
DDX_Text(pDX, IDC_EDIT4, m_num4);
DDX_Text(pDX, IDC_EDIT5, m_num5);
DDX_Text(pDX, IDC_EDIT6, m_num6);
DDX_Text(pDX, IDC_EDIT7, m_num7);
//}}AFX_DATA_MAP
}
DDX_Text函數也被重載,這樣它可以用來處理各種類型的數據。
*/
//************************************************************************


6)好了,編譯運行,怎麼樣成功了吧。如果通過這個小程序您買的彩票中了獎,別忘了告訴雷神一聲。
  注意,程序運行需等待一段時間,下一步可以改進程序例如在程序運行過程中使鼠標指針變成“沙漏”,或加入一個進度條控件,有興趣的朋友可以一試。
今天我們了解了對話框和控件應用的基本方法,其實書上的例子更適合大家了解對話框和控件的應用,雷神寫這個例子的目的是讓大家尤其是初學者知道,VC雖然很不容易學好,但以我們掌握的知識,也可以用它做一些程序,雖然很小,但很實用。如果你還沒有信心不妨寫個計算器,我相信你一定會成功。下一回我們將進一步學習模式對話框和通用控件,我們將學習對話框和視圖相連,以及一些高級控件,和對話框的改進。

未完待續

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