荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: cay (忧郁的年头), 信区: Program
标  题: 『VC++技术内幕』学习笔记(9)  作者 雷神
发信站: 荔园晨风BBS站 (Thu Jan 10 10:45:36 2002), 转信

原作者姓名 雷神
文章原始出处 http://www.ai361.com
正文
『VC++技术内幕』学习笔记(9)
雷神
第九篇:模式对话框和通用控件(上)
对话框是一个真正的窗口,它不但可以接受消息,而且可以被移动和关闭,还可以
在它的客户区中进行绘图操作。对话框可以分为模式对话框和无模式对话框两种,
两者区别是在对话框被关闭之前用户能否在同一应用程序的其他地方进行工作。举
例说明:打开文件对话框便是典型的模式对话框,在你选择好要打开的文件按下确
定后,或者取消打开文件操作后,才可以在同一应用程序进行其他操作。而常见的
查找和替换对话框便是无模式对话框的典型,在该对话框打开的同时,我们还可以
进行其他工作。
对话框属于一种资源,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虽然很
不容易学好,但以我们掌握的知识,也可以用它做一些程序,虽然很小,但很实用
。如果你还没有信心不妨写个计算器,我相信你一定会成功。下一回我们将进一步
学习模式对话框和通用控件,我们将学习对话框和视图相连,以及一些高级控件,
和对话框的改进。

未完待续
下一篇:模式对话框和通用控件(下)




--

        放弃是最容易的事

        Email: caiji@163.net          QQ: 80123

※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.1.168]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店