MFC——“依米魔法邮箱”开发笔记

“依米魔法邮箱”开发笔记

软件用MFC开发而成,具体有以下功能、特色:

  • 文档加密解密
  • 保存自定义后缀的文件(*.yimi)
  • 打开自定义后缀的文件(*.yimi)
  • 改变窗口背景色
  • 改变窗口形状
  • 改变光标图案
  • 生成动态自定义软件图标

效果图如下

“依米魔法邮箱”运行效果

功能实现方法

我所选的是MFC基本对话框类型的应用程序,布局如下:
对话框布局

文档加密解密

加密核心代码:

//加密
    char str;
    for(int i = 0; i < m_strContent.GetLength(); i++)
    {
        str = m_strContent.GetAt(i);
        str = str+i;
        m_strContent.SetAt(i, str);
    }

解密核心代码:

//判断是否是.yimi文件
    if(dlg.GetFileExt()=="yimi")//是.yimi文件,则解密
    {//解密
        char str;
        for(int i = 0; i < m_strContent.GetLength(); i++)
        {
            str = m_strContent.GetAt(i);
            str = str-i;
            m_strContent.SetAt(i, str);
        }

        UpdateData(FALSE);//更新数据
    }

具体请参见下面的“保存与打开自定义后缀的文件”。

保存自定义后缀的文件(*.yimi)

为编辑框空间关联Value类型的CString变量m_strContent;
为顶部静态文本关联Value类型的CString变量m_strTitle;
为“另存为”按钮添加BN_CLICKED消息映射,并添加映射函数,代码如下(包括保存文件、顶部显示文件相关信息和对*.yimi类型的文件进行加密处理):

void CMyDlg::OnButtonSave() 
{
    CFile file;
    CString filter;
    //“依米魔法文件(*.yimi)”即文件类型选择项,“*.yimi”即要求显示的类型文件
    filter = "依米魔法文件(*.yimi)|*.yimi||";
    //第一个参数为TRUE时为“打开文件”对话框;为FALSE时为“另存为”对话框。
    CFileDialog dlg(FALSE, filter, NULL, OFN_HIDEREADONLY, filter);
    if(dlg.DoModal()!=IDOK) return;
    //要写CFile::modeCreate,若无该文件则创建;要写CFile::modeWrite,若已有该同名文件则重写覆盖
    if(!file.Open(dlg.GetPathName(), CFile::modeCreate|CFile::modeWrite))
    {
        AfxMessageBox(dlg.GetPathName() + "保存失败╮(╯▽╰)╭");
        return;
    }
    UpdateData();

    //静态文本
    CString strFileName = dlg.GetPathName();
    CFileStatus status;
    if(!CFile::GetStatus(strFileName, status))
    {
        MessageBox("该文件不存在!");
        return;
    }
    //为顶端静态文本设置为以下格式的内容:文件路径全名[年-月-日, 字节数]
    m_strTitle.Format("%s[%s, %ld字节]", strFileName,
        status.m_ctime.Format("%Y-%m-%d"), status.m_size);
    UpdateData(FALSE);

    //加密
    char str;
    for(int i = 0; i < m_strContent.GetLength(); i++)
    {
        str = m_strContent.GetAt(i);
        str = str+i;
        m_strContent.SetAt(i, str);
    }

    //文档保存
    file.Write(m_strContent, m_strContent.GetLength());
    file.Close();

}

打开自定义后缀的文件(*.yimi)

为“打开”按钮添加BN_CLICKED消息映射,并添加映射函数,代码如下(包括打开文件、顶部显示文件相关信息和对*.yimi类型的文件进行解密)

void CMyDlg::OnButtonOpen() 
{
    CString filter;
    //“依米魔法文件(*.yimi)”即文件类型选择项,“*.yimi”即要求显示的类型文件
    filter = "依米魔法文件(*.yimi)|*.yimi|(*.*)|*.*||";
    //第一个参数为TRUE时为“打开文件”对话框;为FALSE时为“另存为”对话框。
    CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY, filter);
    if(dlg.DoModal()!=IDOK) return;
    //静态文本
    CString strFileName = dlg.GetPathName();
    CFileStatus status;
    if(!CFile::GetStatus(strFileName, status))
    {
        MessageBox("该文件不存在!");
        return;
    }

    //为顶端静态文本设置为以下格式的内容:文件路径全名[年-月-日, 字节数]
    m_strTitle.Format("%s[%s, %ld字节]", strFileName,
        status.m_ctime.Format("%Y-%m-%d"), status.m_size);
    UpdateData(FALSE);//更新数据

    //打开文件,并读取数据
    m_strContent.Empty();   //清空内容
    CFile theFile;
    if(!theFile.Open(strFileName, CFile::modeRead))
    {
        MessageBox("该文件无法打开!");
        return;
    }
    char szBuffer[80];
    UINT nActual = 0;
    while(nActual = theFile.Read(szBuffer, sizeof(szBuffer)))
    {
        CString str(szBuffer, nActual);
        m_strContent = m_strContent + str;
    }
    theFile.Close();

    //判断是否是.yimi文件
    if(dlg.GetFileExt()=="yimi")//是.yimi文件,则解密
    {//解密
        char str;
        for(int i = 0; i < m_strContent.GetLength(); i++)
        {
            str = m_strContent.GetAt(i);
            str = str-i;
            m_strContent.SetAt(i, str);
        }

        UpdateData(FALSE);//更新数据
    }
} 

改变窗口背景色

用MFC ClassWizard向导为CMyDlg类添加WM_CTLCOLOR消息映射,并添加以下代码:

HBRUSH CMyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{
    HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

    COLORREF color = RGB(180, 227, 239);//天蓝色
    m_Brush.Detach();
    m_Brush.CreateSolidBrush(color);
    pDC->SetBkColor(color);

//  return hbr; //只编辑框有背景颜色

    return (HBRUSH)m_Brush;//整个窗体的背景色
}

改变窗口形状

在ResourceView中添加Bitmap资源,ID设为IDB_BITMAP_DLG。注意,白色为将来可显示的窗体部分,其他色均为透明显示,所绘制的Bitmap图形大小应与窗体实际大小一致。
窗体实际大小
添加Bitmap资源

绘制如图:
绘制Bitmap资源
然后在BOOL CMyDlg::OnInitDialog()函数的return TRUE;语句前添加如下代码:

//异形窗体
    COLORREF TransColor=RGB(255,255,255);//白色为显示的部分  
    CBitmap cBitmap;  
    cBitmap.LoadBitmap(IDB_BITMAP_DLG);//加载描述窗口形状的BMP图片  
    CDC* pDC=this->GetDC();  
    CDC memDC;  
    memDC.CreateCompatibleDC(pDC);//创建与传入DC兼容的临时DC  
    CBitmap *pOldMemBmp=NULL;  
    pOldMemBmp=memDC.SelectObject(&cBitmap);//将位图选入临时DC,方便对图片在控件环境中进行操作  
    static CRgn wndRgn;  
    wndRgn.CreateRectRgn(0,0,0,0);//创建总的窗体区域,初始region为0  
    BITMAP bit;  
    cBitmap.GetBitmap (&bit);//取得位图参数,这里要用到位图的长和宽  
    int y;  
    CRgn rgnTemp; //保存临时region  
    for(y=0;y<=bit.bmHeight ;y++)  
    {  
        int iX = 0;  
        do  
        {  
            //跳过透明色找到下一个非透明色的点.  
            while (iX <= bit.bmWidth && memDC.GetPixel(iX, y) != TransColor)  
                iX++;  
            //记住这个起始点  
            int iLeftX = iX;  
            //寻找下个透明色的点  
            while (iX <= bit.bmWidth && memDC.GetPixel(iX, y) == TransColor)  
                ++iX;  
            //创建一个包含起点与重点间高为1像素的临时“region”  
            rgnTemp.CreateRectRgn(iLeftX, y, iX, y+1);  
            //合并到主"region".  
            wndRgn.CombineRgn(&wndRgn, &rgnTemp, RGN_OR);  
            //删除临时"region",否则下次创建时和出错  
            rgnTemp.DeleteObject();  
        }while(iX<bit.bmWidth);  
    }  
    this->SetWindowRgn(wndRgn,TRUE);  
    memDC.DeleteDC(); 

具体请参见

MFC异形窗口-多边形窗口-根据图片自定义窗口形状-CRgn

最终效果如图:
效果图

改变光标图案

在ResourceView的Cursor下绘制一个光标资源,ID默认为IDC_CURSOR1。单击“新建设备图像”按钮新建设备图像 单击“自定义”按钮设置好大小颜色后按“确定”。注意:很重要的一点,接下来要在“设备”选项中选择系统原来默认已有的“单色[32*32]”,然后选择“图像”菜单的“删除设备图像”命令。这样才能把我们自定义的光标正常使用。

绘制Cursor资源
接下来,为CMyDlg类添加HCURSOR类型的成员变量m_hCursor,并为CMyDlg类添加WM_SETCURSOR的消息映射函数,代码如下:

BOOL CMyDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
{
    if(nHitTest == HTCAPTION)
    {
        m_hCursor = AfxGetApp()->LoadCursor(IDC_CURSOR1);
        SetCursor(m_hCursor);
    }else if(nHitTest == HTCLIENT)
    {
        m_hCursor = AfxGetApp()->LoadCursor(IDC_CURSOR1);
        SetCursor(m_hCursor);
    }
    return true;
}

生成动态自定义软件图标

在ResourceView的Icon下添加若干图标资源,如下:
Icon1
Icon2
Icon3
Icon4
为CMyDlg添加成员函数ChangeIcon(UINT nIconID),代码如下:

void CMyDlg::ChangeIcon(UINT nIconID)
{
    HICON hIconNew = AfxGetApp()->LoadIcon(nIconID);
    HICON hIconOld = (HICON)GetClassLong(m_hWnd, GCL_HICON);
    if(hIconNew!=hIconOld)
    {
        DestroyIcon(hIconOld);
        SetClassLong(m_hWnd, GCL_HICON, (long)hIconNew);
        RedrawWindow();
    }
}

接下来,要实现动画效果,即软件图标不断变化,需要用到计时器。
在BOOL CMyDlg::OnInitDialog()中添加计时器设置代码:

SetTimer(1, 500, NULL);//改图标

其中第一个参数指定改计时器标识值,任写一个非零数字即可;第二个参数表示调用计时器的时间间隔,此处为以500毫秒的时间为间隔更换图标,从而实现动画效果;第三个参数是一个回调函数指针,一般设为NULL即可。
接下来,为CMyDlg添加WM_TIMER的消息映射函数,代码如下:

void CMyDlg::OnTimer(UINT nIDEvent) 
{
    if(nIDEvent==1)
    {//改图标,nIDEvent即SetTimer函数的第一个参数——计时器标识值
        static int icons[] = {IDI_ICON1, IDI_ICON2, IDI_ICON3, IDI_ICON4};//图标
        static int index = 0;
        ChangeIcon(icons[index]);
        index++;
        if(index>3) index = 0;  
    }

    CDialog::OnTimer(nIDEvent);
}

接下来,为CMyDlg添加WM_DESTROY的消息映射函数,代码如下:

void CMyDlg::OnDestroy() 
{
    CDialog::OnDestroy();
    KillTimer(1);   
}

OK,可以运行看结果啦~

源码及程序下载

下载源码及程序

发布了40 篇原创文章 · 获赞 41 · 访问量 8万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章