打造自己的專業圖像工具-Visual C++ 2005圖像編程系列【五】(中)

現在,我們還沒有看字體枚舉的回調函數是如何工作的。回調函數裏每次回調一個新的字體就需要創建一個CFontInfo對象,並寫入相應的信息,然後添加到CFontComboBox的成員m_pFontVec中。在這個回調的靜態函數裏就需要訪問CFontComboBox 對象,原來在調用這個函數的時候我們把一個CFontComboBox 對象的this指針通過LPARAM參數傳入了回調函數。一切就都不是問題了。

int CFontComboBox::EnumFontProc(ENUMLOGFONTEX *lpelfe,

                                                        NEWTEXTMETRICEX *lpntme,

                                                        DWORD FontType,

                                                        LPARAM lParam)

{

       CFontComboBox *pThis = reinterpret_cast<CFontComboBox*>(lParam);

       CFontInfo *pInfo = new CFontInfo;

       pInfo->SetFontType(FontType);

       pInfo->SetFontName(lpelfe->elfLogFont.lfFaceName);

       DWORD dwFontType = FontType;

       if (FontType & TRUETYPE_FONTTYPE)

       {

              DWORD dwFontFlags = lpntme->ntmTm.ntmFlags;

              if (dwFontFlags & NTM_PS_OPENTYPE)

                     dwFontType |= PS_OPENTYPE_FONTTYPE;

              else

                     dwFontType |=0;

              if (dwFontFlags & NTM_TT_OPENTYPE)

                     dwFontType |= TT_OPENTYPE_FONTTYPE;

              else

                     dwFontType |=0;

              dwFontType |= (dwFontFlags & NTM_TYPE1 ? TYPE1_FONTTYPE : 0);

       }

       switch(dwFontType & 0x70007)

       {

       case (TRUETYPE_FONTTYPE | PS_OPENTYPE_FONTTYPE):

       case (TRUETYPE_FONTTYPE | TT_OPENTYPE_FONTTYPE):

       case (TRUETYPE_FONTTYPE | TYPE1_FONTTYPE):

              pInfo->SetImage(3);             break;

       case RASTER_FONTTYPE:

       case DEVICE_FONTTYPE:

    case NULL:    pInfo->SetImage(0XFF);      break;

       case TRUETYPE_FONTTYPE:

       default:           pInfo->SetImage(0);             break;

       }

       pThis->m_pFontVec.push_back(pInfo);

       return TRUE;

}

       注意在上面使用的字體類型定義,需要在EnumFontProc函數前面直接加上如下的預編譯定義:

#ifndef   NTM_PS_OPENTYPE

#define   NTM_PS_OPENTYPE                0x00020000

#endif

#ifndef   NTM_TT_OPENTYPE

#define   NTM_TT_OPENTYPE                0x00040000

#endif

#ifndef   PS_OPENTYPE_FONTTYPE

#define   PS_OPENTYPE_FONTTYPE      0x10000

#define   TT_OPENTYPE_FONTTYPE      0x20000

#define   TYPE1_FONTTYPE                   0x40000

#endif

接下來我們看看如何設置下面列表框的寬度,當用戶點擊小箭頭顯示下拉框時,會發出CBN_DROPDOWN消息,我們需要在這個消息函數裏設置下拉框的寬度。先在MFC的消息宏中添加消息映射:

BEGIN_MESSAGE_MAP(CFontComboBox, CComboBox)

       ON_CONTROL_REFLECT(CBN_DROPDOWN, OnDropdown)

       ON_WM_DESTROY()

END_MESSAGE_MAP()

       OnDropdown函數裏我們要計算所有字體名稱字符串的長度,用最大值做爲下拉框的顯示寬度,最好的顯示寬度還要加上滾動條和左邊的字體圖片的寬度,爲了方便使用,還定義了兩個字體預覽圖的寬度、高度值:

#define           FNTIMG_X                 20

#define           FNTIMG_Y                  12

void CFontComboBox::OnDropdown()

{

       int nNumEntries = GetCount();

    int nWidth = 0;

    CString str;

    CClientDC dc(this);

    int nSave = dc.SaveDC();

    dc.SelectObject(GetFont());

    int nScrollWidth = ::GetSystemMetrics(SM_CXVSCROLL);      //取滾動條寬度

    for (int i = 0; i < nNumEntries; i++)

    {

        GetLBText(i, str);

        int nLength = dc.GetTextExtent(str).cx + nScrollWidth;

        nWidth = max(nWidth, nLength);

    }

    nWidth += dc.GetTextExtent("0").cx;

    dc.RestoreDC(nSave);

       if (!m_pFontVec.empty())

              SetDroppedWidth(nWidth + FNTIMG_XSIZE);                 //設置寬度值

}

       還記得上面枚舉函數裏我們用new動態申請了很多的字體信息CFontInfo對象,這些對象在窗口退出時需要釋放,否則會內存泄漏。釋放這些東西的位置就在窗口WM_DESTROY消息函數裏。這個消息是最理想的清除地方。

應用程序關閉過程:

當用戶按下菜單的close命令時,系統發出WM_CLOSE,通常程序的窗口函數不攔截這個消息,於是DefWinodwProc處理它,DefWinodwProc收到WM_CLOSE後,調用DestroyWindow把窗口清除,DestroyWindow本身會送出WM_DESTROY,程序對WM_DESTROY的標準反應就是調用PostQuitMessagePostQuitMessage沒有其他的操作,就只送出WM_QUIT消息,而消息循環GetMessage得到這個消息後返回0,而結束了消息循環,再接着結束整個程序。在實際運用中,有的時候我們的程序窗口關閉了,但是在任務管理器裏還有進程存在,這個問題有時候就是因爲沒有調用PostQuitMessage(0);引起的。

 

void CFontComboBox::OnDestroy()

{

       for (int i=0; i<m_pFontVec.size(); ++i)

              delete m_pFontVec[i];

       m_pFontVec.erase(m_pFontVec.begin(), m_pFontVec.end());

       CComboBox::OnDestroy();

}

 在釋放STL的很多指針容器時,容器對象的erase函數只是釋放每個指針所佔用的控件,並且釋放我們new的指針對象,所以在erase之前要先delete每個對象指針。
發佈了77 篇原創文章 · 獲贊 0 · 訪問量 36萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章