1.12 通用对话框的应用

通用对话框是由操作系统提供的任何应用程序都可获得的对话框,使用这些对话框,可以为用户提供他们所期望的一致性的标准界面。在Visual C++中,这些对话框被封装在CCommonDialog及其派生类中。本节中的实例实现了通用对话框的应用。

实例035 打开位图预览对话框

本实例是一个提高效率的程序

实例位置:光盘\mingrisoft\01\035

实例说明

在使用打开对话框选择图片时,如果能够对图片进行预览就可以让用户更加快捷地选择想要的图片。运行本实例,单击“打开”按钮,在弹出的“打开”对话框中选择一个BMP位图资源,用户可以在“打开”对话框的下方看到该位图的预览图像以及图像尺寸、文件大小和创建时间等信息,效果如图1.45所示。

技术要点

文件对话框CFileDialog有一个数据成员m_ofn,该成员为OPENFILENAME结构变量。OPENFILENAME结构包含了一组成员,其中Flags是初始化对话框的一组标记,lpTemplateName用于提供文件对话框的子对话框窗口,如果Flags中包含OFN_EXPLORER标记,系统将创建一个标准对话框的子对话框。如果用户想要设计自己的文件对话框,可以创建一个新的对话框,在新的对话框中添加控件,然后将其赋给lpTemplateName成员。在这里有一点需要注意,如果文件对话框的子窗口采用了用户提供的对话框,则系统为文件对话框提供的标准控件也将显示在对话框中。因此,用户在向对话框中添加控件时,需要调整控件的位置。可以采用这样一种方式:在对话框中放置一个CStatic控件,将其ID设置为“stc32”。“stc32”是系统预定的标记,它用来确定标准文件对话框中控件显示的位置,用户可以依据它来放置自己添加的控件。

图1.45 半透明窗体

实现过程

(1)新建一个基于对话框的应用程序。

(2)向对话框中添加一个按钮控件,设置其Caption属性为“打开”。

(3)新建一个对话框资源,向新建的对话框中添加1个图片控件和3个静态文本控件。

(4)以CFileDialog类为基类派生一个CNewFileDialog类。

(5)在CNewFileDialog类的头文件中声明变量,代码如下:

            CStatic m_Bitmap;                                //图片控件对应变量
            CStatic m_Measure;                               //图像尺寸控件对应变量
            CStatic m_Size;                                  //文件大小控件对应变量
            CStatic m_Time;                                  //创建时间控件对应变量

(6)在CNewFileDialog类的构造函数中设置m_ofn成员,代码如下:

        CNewFileDialog::CNewFileDialog(BOOL bOpenFileDialog, LPCTSTR lpszDefExt, LPCTSTR lpszFileName,
                  DWORD dwFlags, LPCTSTR lpszFilter, CWnd* pParentWnd) :
                  CFileDialog(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, pParentWnd)
        {
            m_ofn.Flags = (OFN_EXPLORER| OFN_ENABLETEMPLATE| OFN_ENABLEHOOK);
            //将对话框资源赋给lpTemplateName成员
            m_ofn.lpTemplateName = MAKEINTRESOURCE(IDD_NEWFILE_DIALOG);
        }

(7)处理CNewFileDialog类的WM_INITDIALOG消息,将声明的成员关联到对话框中的静态文本控件,代码如下:

        BOOL CNewFileDialog::OnInitDialog()
        {
            CFileDialog::OnInitDialog();
            m_Bitmap.SubclassDlgItem(IDC_STATIC1,this);           //关联图片控件
            m_Measure.SubclassDlgItem(IDC_STATIC2,this);          //关联图像尺寸控件
            m_Size.SubclassDlgItem(IDC_STATIC3,this);             //关联文件大小控件
            m_Time.SubclassDlgItem(IDC_STATIC4,this);             //关联创建时间控件
            return TRUE;
        }

(8)在CNewFileDialog类中,添加OnFileNameChange虚拟方法,在文件改变时,判断选择的文件是否是位图,如果是,则将其显示在图片控件中,并将其信息显示在静态文本控件中,代码如下:

        void CNewFileDialog::OnFileNameChange()
        {
            CString exp;
            exp=GetFileExt();
            exp.MakeUpper();                                                        //在比较扩展名时不区分大小写
            if(exp=="BMP")                                                          //显示位图
            {
                  CFile file;                                                        //声明CFile类对象
                  if(!file.Open(GetPathName(),CFile::modeRead))                     //打开文件
                    return;
                  BITMAPFILEHEADER bmfHeader;
                  if(file.Read((LPSTR)&bmfHeader,sizeof(bmfHeader)) != sizeof(bmfHeader)) //读位图文件头信息
                    return;
                  BITMAPINFOHEADER bmiHeader;
                  if(file.Read((LPSTR)&bmiHeader,sizeof(bmiHeader))!=sizeof(bmiHeader)) //读位图头信息
                    return ;
                  //获得大小信息,并显示
                  int bmWidth=bmiHeader.biWidth;                                     //获得位图宽度
                  int bmHeight=bmiHeader.biHeight;                                   //获得位图高度
                  file.Close();                                                     //关闭文件
                  int x=150,y=150;
                  if(bmWidth<150)                                                   //如果文件宽度小于150像素
                    x=bmWidth;                                                      //设置其显示宽度
                  if(bmHeight<150)                                                  //如果文件高度小于150像素
                    y=bmHeight;                                                     //设置其显示高度
                  m_Bitmap.SetBitmap((HBITMAP)LoadImage(NULL,GetPathName(),
                    IMAGE_BITMAP,x,y,LR_LOADFROMFILE));                             //显示位图
                  CFileStatus status;
                  CFile::GetStatus(GetPathName(),status);                           //获得位图信息
                  CString  measure,size,time;
                  measure.Format("图像尺寸:%d*%d",bmWidth,bmHeight);               //格式化图像尺寸
                  size.Format("文件大小:%dK",status.m_size/1024);                  //格式化文件大小
                  time.Format("创建时间:%s",status.m_ctime.Format("%Y年%m月%d日 %H:%M:%S"));//格式化创建时间
                  m_Measure.SetWindowText(measure);                                 //显示图像尺寸
                  m_Size.SetWindowText(size);                                       //显示文件大小
                  m_Time.SetWindowText(time);                                       //显示创建时间
            }
        }

(9)处理主窗口中“打开”按钮的单击事件,在该事件的处理函数中调用“打开”对话框,代码如下:

            void CBmpPreviewDlg::OnOpen()
            {
            CNewFileDialog dlg(true,NULL,NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT|
                OFN_EXPLORER|OFN_ENABLETEMPLATE,"All Files(*.BMP)|*.BMP||");     //构造打开对话框
            dlg.DoModal();                                                      //显示打开对话框
        }

举一反三

根据本实例,读者可以:

隐藏打开对话框中默认的控件。

实例036 打开Windows新型对话框

本实例是一个提高效率、人性化的程序

实例位置:光盘\mingrisoft\01\036

实例说明

在Windows 2000及以后版本的操作系统中提供了新型的打开对话框,在程序中如何调用新型的打开对话框呢?本实例将实现调用Windows新型打开对话框的功能,实例运行结果如图1.46所示。

图1.46 Windows新型打开对话框

技术要点

可以使用GetOpenFileName函数实现Windows新型打开对话框的调用,在使用GetOpenFileName函数时,需要设置OPENFILENAME结构的参数。

实现过程

(1)新建一个基于对话框的应用程序。

(2)向对话框中添加一个按钮控件,设置控件ID和Caption属性。

(3)主要程序代码如下:

        void CWindowsDialogDlg::OnButtonopen()
        {
            OPENFILENAME fopt ;                                               //声明OPENFILENAME结果
            memset(&fopt, 0, sizeof(fopt));
            fopt.lStructSize=sizeof(OPENFILENAME);                           //设置结构大小
            fopt.Flags      =OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT;//设置标记
            fopt.hwndOwner   =GetSafeHwnd();                                 //窗口句柄
            fopt.lpstrFilter="All Files(*.*)";                                //过滤字符串
            GetOpenFileName(&fopt);                                          //调用打开对话框
        }

举一反三

根据本实例,读者可以:

实现新型保存对话框。

实例037 同时选择多个文件

本实例是人性化的程序

实例位置:光盘\mingrisoft\01\037

实例说明

在使用“打开”对话框时,可以一次性选择多个文件,这样可以方便用户的操作,本实例窗体实现了同时选择多个文件的功能。运行程序,单击“打开”按钮,可以在弹出的“打开”对话框中同时选择多个文件,如图1.47所示。

图1.47 同时选择多个文件

技术要点

使用“打开”对话框同时选择多个文件时,需要在构造“打开”对话框时设置OFN_ ALLOWMULTISELECT属性,构造“打开”对话框通过CFileDialog构造函数来实现,语法如下:

        CFileDialog(BOOL bOpenFileDialog,LPCTSTR lpszDefExt=NULL,LPCTSTR lpszFileName=NULL,DWORD dwFlags=OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,LPCTSTR lpszFilter=NULL,CWnd*pParentWnd=NULL);

参数说明:

● bOpenFileDialog:如果值为TRUE,构造“打开”对话框;为FALSE,构造“另存为”对话框。

● lpszDefExt:用于确定文件默认的扩展名,如果为NULL,没有扩展名被插入到文件名中。

● lpszFileName:确定编辑框中初始化时的文件名称,如果为NULL,编辑框中没有文件名称。

● dwFlags:用于自定义文件对话框。

● lpszFilter:用于指定对话框过滤的文件类型。

● pParentWnd:标识文件对话框的父窗口指针。

注意:lpszFilter参数格式,文件类型说明和扩展名间用“|”分隔,每种文件类型间用“|”分隔,末尾用“||”结束。

在获得“打开”对话框选择的文件路径时,需要使用etStartPosition函数和GetNextPathName函数。

GetStartPosition函数用于获取列表中第一个文件路径名的位置,语法如下:

POSITION GetStartPosition( ) const;

GetNextPathName函数用于从对话框所选的组中获取下一个文件名,文件名路径包括文件标题加上整个目录路径,语法如下:

CString GetNextPathName( POSITION& pos ) const;

由前面GetNextPathName或GetStartPosition函数调用返回的一个POSITION值。如果达到列表尾,则为NULL。

实现过程

(1)新建一个基于对话框的应用程序。

(2)在程序中添加一个列表框控件和一个按钮控件。

(3)主要程序代码如下:

        void CSelectDlg::OnButselect()
        {
            CFileDialog dlg(TRUE,NULL,NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT
                  |OFN_ALLOWMULTISELECT,"All Files(*.*)|*.*||",AfxGetMainWnd());   //构造文件打开对话框
            CString strPath="";                                //声明变量
            if(dlg.DoModal()==IDOK)                           //判断是否按下"打开"按钮
            {
                  POSITION m_Position=dlg.GetStartPosition();  //获取第一个文件名位置
                  while(m_Position != NULL)
                  {
                    strPath = dlg.GetNextPathName(m_Position);//获得下一个文件路径
                    m_List.InsertString(m_List.GetCount(),strPath);//向列表框中插入文件路径
                  }
            }
        }

举一反三

根据本实例,读者可以:

设置文件保存对话框。

实例038 文本替换对话框

本实例是一个提高效率的程序

实例位置:光盘\mingrisoft\01\038

实例说明

使用“查找/替换”对话框可以进行查找和替换操作,CFindReplaceDialog类对“查找/替换”对话框进行了封装,下面通过实例来制作一个文本替换对话框,实例运行结果如图1.48所示。

图1.48 文本替换对话框

技术要点

要使用文本替换对话框,首先要了解CFindReplace Dialog类中封装的各个函数的功能,CFindReplace Dialog类中的常用函数如表1.1所示。

表1.1 CFindReplaceDialog类常用函数表

实现过程

(1)新建一个基于对话框的应用程序。

(2)向对话框中添加一个编辑框控件和一个按钮控件,设置编辑框属性,使其可以多行显示文本,并且具有滚动条。

(3)在对话框头文件中声明变量,代码如下:

        CFindReplaceDialog*dlg;          //声明“查找/替换”对话框指针
            int nindex;                   //存储查找字符串的起始位置
            BOOL degree;                  //判断是否为第一次替换的变量
            BOOL find;                    //判断是否进行查找的变量

(4)定义一个新消息WM_FINDMESSAGE,代码如下:

static UINT WM_FINDMESSAGE = RegisterWindowMessage(FINDMSGSTRING);

(5)在对话框的头文件和消息映射部分分别添加函数定义和映射宏,代码如下:

        afx_msg  long OnFindReplace(WPARAM wParam,LPARAM lParam);
        ON_REGISTERED_MESSAGE(WM_FINDMESSAGE, OnFindReplace )

(6)处理WM_FINDMESSAGE消息,在该消息的响应函数中实现查找和替换操作,代码如下:

        long CReplaceDialogDlg::OnFindReplace(WPARAM wParam, LPARAM lParam)
        {
            CString strText,repText;                               //声明字符串变量
            strText=dlg->GetFindString();                         //获得查找字符串
            CString str;                                           //声明字符串变量
            m_Edit.GetWindowText(str);                            //获得编辑框中的文本
            if(dlg->ReplaceCurrent())                             //判断是否进行替换
                  find=FALSE;                                     //进行替换
            else
                  find=TRUE;                                      //进行查找
            int len;                                               //声明整型变量
            if(find)                                              //判断是查找还是替换
            {
                  len=strText.GetLength();                        //获得要查找字符串的长度
            }
            else
            {
                  if(dlg->ReplaceAll())                           //判断是否全部替换
                  {
                    repText=dlg->GetReplaceString();              //获得替换字符串
                    len   =repText.GetLength();                   //获得替换字符串长度
                    str.Replace(strText,repText);                 //使用替换字符串替换查找字符串
                    m_Edit.SetWindowText(str);                    //将替换后的字符串显示在编辑框中
                  }
                  else
                  {
                    CString left,right;                            //声明字符串变量
                    int num   =strText.GetLength();                //获得查找字符串的长度
                    int strnum=str.GetLength();                    //获得编辑框中文本长度
                    int index;                                     //声明整型变量
                    if(!degree)                                   //判断是否为第一次替换
                        index=str.Find(strText,nindex);           //获得查找字符串在编辑框文本中的位置
                    else if(nindex-2>=0)                           //判断起始查找位置是否小于0
                        index=str.Find(strText,nindex-2);         //获得查找字符串在编辑框文本中的位置
                    else
                    {
                        nindex=2;                                 //设置起始查找位置
                        return 1;
                    }
                    degree = TRUE;
                    left=str.Left(index);                         //获得替换字符串左侧的字符串
                    right=str.Right(strnum-index-num);            //获得替换字符串右侧的字符串
                    repText=dlg->GetReplaceString();              //获得替换字符串
                    len=repText.GetLength();                      //获得替换字符串长度
                    str=left+repText+right;                       //组合成新的字符串
                    m_Edit.SetWindowText(str);                    //在编辑框中显示新的字符串
                  }
            }
            int index=str.Find(strText,nindex);                    //获得查找字符串在编辑框文本中的位置
            m_Edit.SetSel(index,index+len);                       //选中查找或替换的字符串
            nindex=index+len;                                     //设置起始查找位置
            m_Edit.SetFocus();                                    //编辑框获得焦点
            return 0;
        }

(7)为“替换”按钮处理单击事件,创建“替换”对话框的代码如下:

        void CReplaceDialogDlg::OnReplace()  //“替换”按钮单击事件响应函数
        {
            dlg=new CFindReplaceDialog;      //为“查找/替换”对话框指针赋值
            dlg->Create(FALSE,NULL);        //创建“替换”对话框
            dlg->ShowWindow(SW_SHOW);       //显示“替换”对话框
        }

举一反三

根据本实例,读者可以:

设计文件查找对话框。

实例039 字体选择对话框

本实例是一个提高效率的程序

实例位置:光盘\mingrisoft\01\039

实例说明

CFontDialog类封装了Windows字体对话框。用户可以从系统安装的字体列表中选择要用的字体,同时,在“字体”对话框中还可以设置字体大小、颜色、效果、字符集等属性。下面通过实例来演示字体选择对话框,实例运行结果如图1.49所示。

图1.49 字体选择对话框

技术要点

要使用字体对话框就要了解CFontDialog类封装的功能,字体对话框的常用函数如表1.2所示。

表1.2 字体对话框常用函数表

实现过程

(1)新建一个基于对话框的应用程序。

(2)向对话框中添加一个编辑框控件和一个按钮控件,设置编辑框控件属性,使其可以多行显示,并具有滚动条。

(3)在对话框头文件中声明一个CFont对象m_Font。

(4)主要程序代码如下:

        void CFontDialogDlg::OnFont()
        {
            CFont*TempFont=m_Text.GetFont();      //获取编辑框当前字体
            LOGFONT LogFont;
            TempFont->GetLogFont(&LogFont);
            CFontDialog dlg(&LogFont);             //初始化字体信息
            if(dlg.DoModal()==IDOK)
            {
                m_Font.Detach();
                LOGFONT temp;
                  dlg.GetCurrentFont(&temp);           //获取当前字体信息
                  m_Font.CreateFontIndirect(&temp);    //直接创建字体
                  m_Color=dlg.GetColor();              //获得字体颜色
                  m_Text.SetFont(&m_Font);             //设置字体
            }
            }

举一反三

根据本实例,读者可以:

使用字体对话框为对话框中各个控件设置不同的字体。