• 打造自己的专业图像工具-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每个对象指针。
  • 相关阅读:
    一 : Nacos简介
    性能指标:性能监控指标有哪些?
    性能测试的分类
    VLP16线用户手册.md
    LibLas学习笔记
    从深度图中提取物体边界
    从点云数据生成深度图像
    微创社2期:从0到1,技术图书创作3步走(张慧敏、高飞、张杰、王凤辉)
    中国.NET:各地微软技术俱乐部汇总(更新中...)
    编译lua-5.3.5时出错解决方法
  • 原文地址:https://www.cnblogs.com/hehe520/p/6330114.html
Copyright © 2020-2023  润新知