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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章