编程技巧15法之二

    技术2022-05-11  139

       

    1.         如何在指定矩形框内水平/垂直显示多行文字

    ///

    //说明:

    //  在矩形框中水平或垂直显示多行文字,jingzhou xu.

    //  lMode: 排列方式,0:水平方式; 1:垂直对齐      

    //  lHori: 水平对齐方式, 0:左对齐; 1:居中; 2:右对齐; 3:自定义

    //  lVert: 垂直对齐方式, 0:顶对齐; 1:居中; 2:底对齐; 3:自定义

    ///

    CRect DrawTitleInRect(CDC *pDC, CString szString, LPRECT lpRect, long lMode, long lHori, long lVert)

    {

           TEXTMETRIC tm;

           pDC->GetTextMetrics(&tm);

           int tmpWidth=tm.tmAveCharWidth, tmpHeight=tm.tmHeight;

     

           CRect rcInner(lpRect);

           if(lMode==0)

           {

                  rcInner.left+=tmpWidth;

                  rcInner.right-=tmpWidth;

                  rcInner.top-=tmpWidth;

                  rcInner.bottom+=tmpWidth;

           }

           if(lMode==1)

           {

                  rcInner.left+=tmpWidth;

                  rcInner.right=rcInner.left+tmpWidth;

                  rcInner.top-=tmpWidth;

                  rcInner.bottom+=tmpWidth;

           }

     

           pDC->DrawText(szString, rcInner,DT_CALCRECT);

     

           switch(lHori)

           {

           case 0:

                  break;

           case 1:

                  {

                         long xOutCent=(lpRect->right+lpRect->left)/2;

                         long xInnCent=(rcInner.right+rcInner.left)/2;

                         rcInner.left+=(xOutCent-xInnCent);

                         rcInner.right+=(xOutCent-xInnCent);

                  }

                  break;

           case 2:

                  {

                         long lInWidth=rcInner.right-rcInner.left;

                         rcInner.right=lpRect->right-tmpWidth;

                         rcInner.left=rcInner.right-lInWidth;

                  }

                  break;

           default:

                  break;

           }

          

           switch(lVert)

           {

           case 0:

                  break;

           case 1:

                  {

                         long yOutCent=(lpRect->bottom+lpRect->top)/2;

                         long yInnCent=(rcInner.bottom+rcInner.top)/2;

                         rcInner.top-=(yInnCent-yOutCent);

                         rcInner.bottom-=(yInnCent-yOutCent);

                  }

                  break;

           case 2:

                  {

                         long lInHeigh=rcInner.top-rcInner.bottom;

                         rcInner.bottom=lpRect->bottom+tmpWidth;

                         rcInner.top=rcInner.bottom+lInHeigh;

                  }

                  break;

           default:

                  break;

           }

     

           //---------------------------------------------------------------------------------------------

           //功能:根据新、老矩形,重新计算行数,使文字多行显示,jingzhou xu

           //---------------------------------------------------------------------------------------------

           //一行中最大字符数

           int nMaxLineChar = abs(lpRect->right - lpRect->left) / tmpWidth ;             

           //记录当前行的宽度

           short theLineLength=0;

           //记录当前行中汉字字节数,以防止将一半汉字分为两行

           unsigned short halfChinese=0;

     

           for(int i=0; i<=szString.GetLength()-1; i++)

           {

                  if(((unsigned char)szString.GetAt(i) == 0x0d) && ((unsigned char)szString.GetAt(i+1) == 0x0a))

                         theLineLength=0;

     

                  //大于0xa1的字节为汉字字节

                  if((unsigned char)szString.GetAt(i) >= 0xA1)

                         halfChinese++;

                  theLineLength++;

     

                  //如果行宽大于每行最大宽度,进行特殊处理

                  if(theLineLength > nMaxLineChar)

                  {

                         //防止将一个汉字分为两行,回溯

                         if(halfChinese%2)

                         {

                                szString.Insert(i,(unsigned char)0x0a);

                                szString.Insert(i,(unsigned char)0x0d);

                         }

                         else

                         {

                                szString.Insert(i-1,(unsigned char)0x0a);

                                szString.Insert(i-1,(unsigned char)0x0d);

                         }

                        

                         theLineLength = 0;

                  }

           }

     

           //重新计算矩形边界范围

    //     int tmpLine = int(abs(szString.GetLength()*tmpWidth / abs(lpRect->right - lpRect->left)-0.5));

    //       tmpLine += (szString.GetLength()*tmpWidth % abs(lpRect->right - lpRect->left))? 1 : 0;

    //       if(tmpLine == 0)

    //            tmpLine = 1;

           if(rcInner.bottom > lpRect->bottom)

                  rcInner.bottom = lpRect->bottom;

           if(rcInner.top < lpRect->top)

                  rcInner.top = lpRect->top;

     

           //---------------------------------------------------------------------------------------------

     

           if(lHori==0)

                  pDC->DrawText(szString, rcInner, DT_WORDBREAK|DT_LEFT);

           else if(lHori==1)

                  pDC->DrawText(szString, rcInner, DT_WORDBREAK|DT_CENTER);

           else if(lHori==2)

                  pDC->DrawText(szString, rcInner, DT_WORDBREAK|DT_RIGHT);

     

           return rcInner;

    }

     

    2.         如何在指定矩形中旋转显示文字

    ///

    //说明:

    //  在矩形框中旋转方式显示文字,jingzhou xu

    //参数:       

    //  pDC:        DC指针

    //  str:           显示文字

    //  rect:         显示范围

    //  angle:        旋转角度

    //       nOptions:       ExtTextOut()中相应设置<ETO_CLIPPED ETO_OPAQUE>

    ///

    void DrawRotatedText(CDC* pDC, const CString str, CRect rect,

                         double angle, UINT nOptions)

    {

       //按比例转换角度值

       double pi = 3.141592654;

       double radian = pi * 2 / 360 * angle;

     

       //获取显示文字中心点

       CSize TextSize = pDC->GetTextExtent(str);

       CPoint center;

       center.x = TextSize.cx / 2;

       center.y = TextSize.cy / 2;

     

       //计算显示文字新的中心点

       CPoint rcenter;

       rcenter.x = long(cos(radian) * center.x - sin(radian) * center.y);

       rcenter.y = long(sin(radian) * center.x + cos(radian) * center.y);

     

       //绘制文字

       pDC->SetTextAlign(TA_BASELINE);

       pDC->SetBkMode(TRANSPARENT);

       pDC->ExtTextOut(rect.left + rect.Width() / 2 - rcenter.x,

                       rect.top + rect.Height() / 2 + rcenter.y,

                       nOptions, rect, str, NULL);

    }

     

    3.         如何将32 x 32像素图标转换为16 x 16像素值的图标

    HICON Convert32x32IconTo16x16(HICON h32x32Icon)

    {

      HDC hMainDC, hMemDC1, hMemDC2;

      HICON h16x16Icon;

      BITMAP bmp;

      HBITMAP hOldBmp1, hOldBmp2;

      ICONINFO IconInfo32x32, IconInfo16x16;

     

      GetIconInfo(h32x32Icon, &IconInfo32x32);

     

      hMainDC = ::GetDC(m_hWnd);

      hMemDC1 = CreateCompatibleDC(hMainDC);

      hMemDC2 = CreateCompatibleDC(hMainDC);

     

      GetObject(IconInfo32x32.hbmColor, sizeof(BITMAP), &bmp);

     

      IconInfo16x16.hbmColor = CreateBitmap( 16, 16,

                                             bmp.bmPlanes,

                                             bmp.bmBitsPixel,

                                             NULL);

     

      hOldBmp1 = (HBITMAP) SelectObject( hMemDC1,

                                         IconInfo32x32.hbmColor);

      hOldBmp2 = (HBITMAP) SelectObject( hMemDC2,

                                         IconInfo16x16.hbmColor);

     

      StretchBlt(hMemDC2,

           0, 0,

           16, 16,

           hMemDC1,

           0, 0,

           32, 32,

           SRCCOPY

           );

     

      GetObject(IconInfo32x32.hbmMask, sizeof(BITMAP), &bmp);

     

      IconInfo16x16.hbmMask = CreateBitmap( 16, 16,

                                            bmp.bmPlanes,

                                            bmp.bmBitsPixel,

                                            NULL);

     

      SelectObject(hMemDC1, IconInfo32x32.hbmMask);

      SelectObject(hMemDC2, IconInfo16x16.hbmMask);

     

      StretchBlt(hMemDC2,

                 0, 0,

                 16, 16,

                 hMemDC1,

                 0, 0,

                 32, 32,

                 SRCCOPY

           );

     

      SelectObject(hMemDC1, hOldBmp1);

      SelectObject(hMemDC2, hOldBmp2);

     

      IconInfo16x16.fIcon = TRUE;

      h16x16Icon = CreateIconIndirect(&IconInfo16x16);

     

      DeleteObject(IconInfo32x32.hbmColor);

      DeleteObject(IconInfo16x16.hbmColor);

      DeleteObject(IconInfo32x32.hbmMask);

      DeleteObject(IconInfo16x16.hbmMask);

      DeleteDC(hMemDC1);

      DeleteDC(hMemDC2);

      ::ReleaseDC(m_hWnd, hMainDC);

     

      return h16x16Icon;

    }

     

    4.         如何建立一个灰度级图标

    HICON CreateGrayscaleIcon(HICON hIcon)

    {

      HICON       hGrayIcon = NULL;

      HDC         hMainDC = NULL,

                  hMemDC1 = NULL,

                  hMemDC2 = NULL;

      BITMAP      bmp;

      HBITMAP     hOldBmp1 = NULL,

                  hOldBmp2 = NULL;

      ICONINFO    csII, csGrayII;

      BOOL        bRetValue = FALSE;

     

      bRetValue = ::GetIconInfo(hIcon, &csII);

      if (bRetValue == FALSE) return NULL;

     

      hMainDC = ::GetDC(m_hWnd);

      hMemDC1 = ::CreateCompatibleDC(hMainDC);

      hMemDC2 = ::CreateCompatibleDC(hMainDC);

      if (hMainDC == NULL ||

        hMemDC1 == NULL ||

        hMemDC2 == NULL)

          return NULL;

     

      if (::GetObject(csII.hbmColor,

                    sizeof(BITMAP), &

                    amp;bmp))

      {

        csGrayII.hbmColor =

             ::CreateBitmap(csII.xHotspot*2,

                            csII.yHotspot*2,

                            bmp.bmPlanes,

                            bmp.bmBitsPixel,

                            NULL);

        if (csGrayII.hbmColor)

        {

          hOldBmp1 =

             (HBITMAP)::SelectObject(hMemDC1,

                                     csII.hbmColor);

          hOldBmp2 =

             (HBITMAP)::SelectObject(hMemDC2,

                                     csGrayII.hbmColor);

     

          ::BitBlt(hMemDC2, 0, 0, csII.xHotspot*2,

                   csII.yHotspot*2, hMemDC1, 0, 0,

                   SRCCOPY);

     

          DWORD    dwLoopY = 0, dwLoopX = 0;

          COLORREF crPixel = 0;

          BYTE     byNewPixel = 0;

     

          for (dwLoopY = 0; dwLoopY < csII.yHotspot*2; dwLoopY++)

          {

            for (dwLoopX = 0; dwLoopX < csII.xHotspot*2; dwLoopX++)

            {

              crPixel = ::GetPixel(hMemDC2, dwLoopX, dwLoopY);

     

              byNewPixel = (BYTE)((GetRValue(crPixel) * 0.299) +

                   (GetGValue(crPixel) * 0.587) +

                   (GetBValue(crPixel) * 0.114));

              if (crPixel) ::SetPixel(hMemDC2,

                                      dwLoopX,

                                      dwLoopY,

                                      RGB(byNewPixel,

                                      byNewPixel,

                                      byNewPixel));

            } // for

          } // for

     

          ::SelectObject(hMemDC1, hOldBmp1);

          ::SelectObject(hMemDC2, hOldBmp2);

     

          csGrayII.hbmMask = csII.hbmMask;

     

          csGrayII.fIcon = TRUE;

          hGrayIcon = ::CreateIconIndirect(&csGrayII);

        } // if

     

        ::DeleteObject(csGrayII.hbmColor);

        //::DeleteObject(csGrayII.hbmMask);

      } // if

     

      ::DeleteObject(csII.hbmColor);

      ::DeleteObject(csII.hbmMask);

      ::DeleteDC(hMemDC1);

      ::DeleteDC(hMemDC2);

      ::ReleaseDC(m_hWnd, hMainDC);

     

      return hGrayIcon;

    }

     

    5.         如何按指定角度旋转显示内存位图(用法和BitBlt类似)

    void RotBlt(HDC destDC, int srcx1, int srcy1, int srcx2, int srcy2,

      HDC srcDC , int destx1, int desty1 ,int thetaInDegrees ,DWORD mode)

    {

      double theta = thetaInDegrees * (3.14159/180);

     

      //原图像原始大小

      int width = srcx2 - srcx1;

      int height = srcy2 - srcy1;

     

      //原图像中心点

      int centreX = int(float(srcx2 + srcx1)/2);

      int centreY = int(float(srcy2 + srcy1)/2);

     

      //判断出图像可以沿任意方向旋转的矩形框

      if(width>height)height = width;

      else

        width = height;

     

     

      HDC memDC = CreateCompatibleDC(destDC);

      HBITMAP memBmp = CreateCompatibleBitmap(destDC, width, height);

     

      HBITMAP obmp = (HBITMAP) SelectObject(memDC, memBmp);

     

      //内存DC新在中心点

      int newCentre = int(float(width)/2);

     

      //开始旋转

      for(int x = srcx1; x<=srcx2; x++)

        for(int y = srcy1; y<=srcy2; y++)

        {

          COLORREF col = GetPixel(srcDC,x,y);

     

          int newX = int((x-centreX)*sin(theta)+(y-centreY)*cos(theta));

          int newY = int((x-centreX)*cos(theta)-(y-centreY)*sin(theta));

     

     

          SetPixel(memDC , newX + newCentre, newY + newCentre, col);

        }

     

      //复制到目标DC上

      BitBlt(destDC, destx1, desty1, width, height, memDC, 0,0,mode);

     

     

      //释放内存

      SelectObject(memDC, obmp);

     

      DeleteDC(memDC);

      DeleteObject(memBmp);

    }

     

    用法:

    RotBlt(dc, 0,0,150,150,memDC,200,0, 45, SRCCOPY);

     

    6.         如何将指定的窗体,以位图形式复制到系统剪切板上

    void CScreenSnapDlg::toClipboard_Bio(CWnd * wnd, BOOL FullWnd)

    {

         CDC *dc;

         if(FullWnd)

            { /* 抓取整个窗口 */

                   dc = new CWindowDC(wnd);

            } /* 抓取整个窗口 */

         else

            { /* 仅抓取客户区时 */

                   dc = new CClientDC(wnd);

            } /* 仅抓取客户区时 */

     

         CDC memDC;

         memDC.CreateCompatibleDC(dc);

     

         CBitmap bm;

         CRect r;

         if(FullWnd)

            wnd->GetWindowRect(&r);

         else

             wnd->GetClientRect(&r);

     

         CString s;

         wnd->GetWindowText(s);

         CSize sz(r.Width(), r.Height());

         bm.CreateCompatibleBitmap(dc, sz.cx, sz.cy);

         CBitmap * oldbm = memDC.SelectObject(&bm);

         memDC.BitBlt(0, 0, sz.cx, sz.cy, dc, 0, 0, SRCCOPY);

     

         //直接调用OpenClipboard(),而不用wnd->GetParent()->OpenClipboard();

            wnd->OpenClipboard();

     

         ::EmptyClipboard();

         ::SetClipboardData(CF_BITMAP, bm.m_hObject);

         CloseClipboard();

     

            //恢复原始环境

         memDC.SelectObject(oldbm);

         bm.Detach(); 

     

            delete dc;

    }

     


    最新回复(0)