雞啄米在上一節中講了CFont字體類,本節主要講解文本輸出的方法和實例。

       文本輸出過程

       在文本輸出到設備以前,我們需要確定字體、字體顏色和輸出的文本內容等信息。Windows窗口的客戶區由應用程序管理,所以我們還要在應用程序中控制輸出文本的格式,例如后續字符的位置、換行等格式。

       由此,文本的輸出過程大致包括確定字體信息、格式化文本和執行輸出操作三個步驟。下面分別講解。

       1、確定字體信息

       文本在輸出以前應該先確定字體信息,或者是當前正在使用的字體,或者是自定義的字體,之后就可以根據確定的字體來顯示文本或者利用字體信息來設定文本的格式了,例如,我們可以根據當前字體的字符高度來確定下一行字符在什么位置輸出。

       自定義字體可以通過CFont類的創建字體的幾個成員函數完成。獲取當前選擇字體的信息可以使用API函數GetTextMetrics實現,此函數的原型如下:

       BOOL GetTextMetrics(__in   HDC hdc,__out  LPTEXTMETRIC lptm);

       參數hdc為設備上下文的句柄;參數lptm是指向TEXTMETRIC結構體變量的指針,此結構體變量用于接收字體信息。TEXTMETRIC結構體的定義如下:

C++代碼
  1. typedef struct tagTEXTMETRIC {   
  2.   LONG  tmHeight;        // 字符高度   
  3.   LONG  tmAscent;        // 字符基線以上的高度   
  4.   LONG  tmDescent;       // 字符基線以下的高度   
  5.   LONG  tmInternalLeading; // 由tmHeight成員指定的字符高度頂部的空間   
  6.   LONG  tmExternalLeading; // 行間距   
  7.   LONG  tmAveCharWidth;  // 字符的平均寬度   
  8.   LONG  tmMaxCharWidth;  // 字符的最大寬度   
  9.   LONG  tmWeight;        // 字符的粗度   
  10.   LONG  tmOverhang;      // 合成字體間附加的寬度   
  11.   LONG  tmDigitizedAspectX; // 為輸出設備設計的x軸尺寸   
  12.   LONG  tmDigitizedAspectY; // 為輸出設備設計的y軸尺寸   
  13.   TCHAR tmFirstChar;     // 字體中第一個字符值   
  14.   TCHAR tmLastChar;      // 字體中最后一個字符值   
  15.   TCHAR tmDefaultChar;   // 替換字體中沒有的字符   
  16.   TCHAR tmBreakChar;     // 作為分隔符的字符   
  17.   BYTE  tmItalic;        // 非0則表示字體為斜體   
  18.   BYTE  tmUnderlined;    // 非0則表示字體有下劃線   
  19.   BYTE  tmStruckOut;     // 非0則表示字符帶有刪除線   
  20.   BYTE  tmPitchAndFamily;// 字體間距和字體族   
  21.   BYTE  tmCharSet;       // 字符集   
  22. } TEXTMETRIC, *PTEXTMETRIC;  

       2、格式化文本

       格式化文本一般包括兩種,一種是確定文本行中后續文本的位置,另一種是確定換行時下一行文本的位置。

       確定后續文本的位置

       一般我們可以先獲取當前字符串的寬度,根據此寬度確定文本行中后續文本的位置。當前字符串的寬度可以通過API函數GetTextExtentPoint32獲得。GetTextExtentPoint32函數的原型如下:

       BOOL GetTextExtentPoint32(__in   HDC hdc,__in   LPCTSTR lpString,__in   int c,__out  LPSIZE lpSize);

       參數hdc為設備上下文的句柄;參數lpString為指向文本字符串緩存的指針,此字符串不是必須以結束符結尾的,因為參數c指定了長度;參數c為lpString指向的字符串的長度;參數lpSize為指向SIZE結構體變量的指針,此SIZE結構體變量用于接收字符串的寬度和高度信息。SIZE結構體定義如下:

C++代碼
  1. typedef struct tagSIZE {   
  2.   LONG cx;   // 寬度   
  3.   LONG cy;   // 高度   
  4. } SIZE, *PSIZE;  

       已知本字符串的起始水平坐標和寬度,兩者相加即是后續文本的起始坐標。

       確定換行時下一行文本的位置

       由GetTextMetrics函數獲取了當前字體的信息并存入TEXTMETRIC結構體后,通過計算當前文本行的垂直坐標、當前字體的高度和行間距之和,就可以得到換行時下一行的垂直坐標。

       3、執行文本輸出操作

       最后,通過API函數TextOut執行文本輸出操作。TextOut函數的原型如下:

       BOOL TextOut(__in  HDC hdc,__in  int nXStart,__in  int nYStart,__in  LPCTSTR lpString,__in  int cbString);

       參數hdc為設備上下文的句柄;參數nXStart為起始點x坐標;參數nYStart為起始點y坐標;參數lpString為要輸出的文本字符串;參數cbString為字符串中要輸出的字符的數量。

       當然也可以使用設備上下文類CDC的成員函數TextOut來輸出,CDC::TextOut函數的兩種重載形式如下:

       virtual BOOL TextOut(int x,int y,LPCTSTR lpszString,int nCount);
       BOOL TextOut(int x,int y,const CString& str);

       參數x指定文本起始點的x坐標;參數y指定文本起始點的y坐標;參數lpszString為要輸出的文本字符串;參數nCount指定字符串中的字節個數;參數str為包含要輸出的字符的CString對象。

       字體和文本輸出的應用實例

       雞啄米下面給大家演示一個簡單的關于字體和文本輸出的實例。功能就是實現兩個字符串分別在水平方向和垂直方向上定時滾動。實現步驟如下:

       1、創建一個基于對話框的MFC工程,名字設置為“Example48”。

       2、在自動生成的對話框模板IDD_EXAMPLE48_DIALOG中,刪除“TODO: Place dialog controls here.”靜態文本框

       3、在Example48Dlg.h文件中為CExample48類添加成員變量:

C++代碼
  1. int m_nTextX;   // 水平滾動文本的起始點的x坐標   
  2. int m_nTextY;   // 垂直滾動文本的起始點的y坐標   
  3. CFont m_newFont;   // 新字體   
  4. CFont *m_pOldFont; // 選擇新字體之前的字體  

       4、在CExample48Dlg類的構造函數中,初始化新添加的成員變量:

C++代碼
  1. CExample48Dlg::CExample48Dlg(CWnd* pParent /*=NULL*/)   
  2.     : CDialogEx(CExample48Dlg::IDD, pParent)   
  3. {   
  4.     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);   
  5.   
  6.     m_nTextX = 260;   
  7.     m_nTextY = 10;   
  8.     m_pOldFont = NULL;   
  9. }  

       5、在CExample48Dlg對話框初始化函數中,創建新的字體,并開啟定時器

C++代碼
  1. BOOL CExample48Dlg::OnInitDialog()   
  2. {   
  3.     CDialogEx::OnInitDialog();   
  4.   
  5.     // Add "About..." menu item to system menu.   
  6.   
  7.     // IDM_ABOUTBOX must be in the system command range.   
  8.     ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);   
  9.     ASSERT(IDM_ABOUTBOX < 0xF000);   
  10.   
  11.     CMenu* pSysMenu = GetSystemMenu(FALSE);   
  12.     if (pSysMenu != NULL)   
  13.     {   
  14.         BOOL bNameValid;   
  15.         CString strAboutMenu;   
  16.         bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);   
  17.         ASSERT(bNameValid);   
  18.         if (!strAboutMenu.IsEmpty())   
  19.         {   
  20.             pSysMenu->AppendMenu(MF_SEPARATOR);   
  21.             pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);   
  22.         }   
  23.     }   
  24.   
  25.     // Set the icon for this dialog.  The framework does this automatically   
  26.     //  when the application's main window is not a dialog   
  27.     SetIcon(m_hIcon, TRUE);         // Set big icon   
  28.     SetIcon(m_hIcon, FALSE);        // Set small icon   
  29.   
  30.     // TODO: Add extra initialization here   
  31.     // 創建一種新的字體(18點,隸書)   
  32.     m_newFont.CreatePointFont(180, _T("隸書"));   
  33.   
  34.     // 設置定時器,定時時間為200ms   
  35.     SetTimer(1,200,NULL);   
  36.   
  37.     return TRUE;  // return TRUE  unless you set the focus to a control   
  38. }  

       6、修改CExample48Dlg::OnPaint()函數,如果窗口沒有最小化就在指定的位置輸出文本,即在OnPaint函數中if(IsIconic())對應的else大括號內添加相應代碼。CExample48Dlg::OnPaint()函數修改如下:

C++代碼
  1. void CExample48Dlg::OnPaint()   
  2. {   
  3.     if (IsIconic())   
  4.     {   
  5.         CPaintDC dc(this); // device context for painting   
  6.   
  7.         SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);   
  8.   
  9.         // Center icon in client rectangle   
  10.         int cxIcon = GetSystemMetrics(SM_CXICON);   
  11.         int cyIcon = GetSystemMetrics(SM_CYICON);   
  12.         CRect rect;   
  13.         GetClientRect(&rect);   
  14.         int x = (rect.Width() - cxIcon + 1) / 2;   
  15.         int y = (rect.Height() - cyIcon + 1) / 2;   
  16.   
  17.         // Draw the icon   
  18.         dc.DrawIcon(x, y, m_hIcon);   
  19.     }   
  20.     else  
  21.     {   
  22.         CPaintDC dc(this); // device context for painting   
  23.         // 設置m_newFont對象的字體為當前字體,并將之前的字體指針保存到m_pOldFont   
  24.         m_pOldFont = (CFont*)dc.SelectObject(&m_newFont);   
  25.         // 設置   
  26.         dc.SetBkMode(TRANSPARENT); //設置背景為透明!   
  27.         // 設置文本顏色為紅色   
  28.         dc.SetTextColor(RGB(255,0,0));   
  29.         // 在指定位置輸出文本   
  30.         dc.TextOut(m_nTextX,10,_T("歡迎來到雞啄米!"));   
  31.         // 設置文本顏色為綠色   
  32.         dc.SetTextColor(RGB(0,255,0));   
  33.         // 在指定位置輸出文本   
  34.         dc.TextOut(10,m_nTextY,_T("謝謝關注www.vkzldl.live"));   
  35.         // 恢復以前的字體   
  36.         dc.SelectObject(m_pOldFont);   
  37.   
  38.         CDialogEx::OnPaint();   
  39.     }   
  40. }  

       7、在Class View類視圖中找到CExample48Dlg,右鍵點Properties,顯示出其屬性頁,在屬性頁工具欄上點擊Messages按鈕,找到WM_TIMER消息,添加消息響應函數CExample48Dlg::OnTimer(UINT_PTR nIDEvent),并在此函數中修改兩個文本輸出的坐標位置。

C++代碼
  1. void CExample48Dlg::OnTimer(UINT_PTR nIDEvent)   
  2. {   
  3.     // TODO: Add your message handler code here and/or call default   
  4.     LOGFONT logFont;   
  5.     // 獲取m_newFont字體的LOGFONT結構   
  6.     m_newFont.GetLogFont(&logFont);   
  7.   
  8.     // 將m_nTextX的值減5   
  9.     m_nTextX -= 5;   
  10.     // 如果m_nTextX小于10,則文本“歡迎來到雞啄米”回到起始位置   
  11.     if (m_nTextX < 10)   
  12.         m_nTextX = 260;   
  13.   
  14.     // 將m_nTextY的值加一個字符高度   
  15.     m_nTextY += abs(logFont.lfHeight);   
  16.     // 如果m_nTextY大于260,則文本“謝謝關注www.vkzldl.live”回到起始位置   
  17.     if (m_nTextY >260)   
  18.         m_nTextY = 10;   
  19.   
  20.     // 使窗口客戶區無效,之后就會重繪   
  21.     Invalidate();   
  22.   
  23.     CDialogEx::OnTimer(nIDEvent);   
  24. }  

       到這一步,兩個文本就可以分別在水平和垂直方向滾動了。雞啄米再簡單解釋下這個過程:程序剛啟動時,會調用OnPaint函數,在初始位置繪出兩個文本,然后每次到了定時器的定時時間后,會執行OnTimer函數,修改兩個文本的坐標值,并通過Invalidate使窗口重繪,又會重新調用OnPaint函數繪制兩個文本。這樣通過定時修改坐標值就實現了兩個文本的滾動效果。

       8、運行程序,最終的效果如下圖:

VS2010/MFC字體和文本輸出實例

       好了,本節就講到這里了,最后的實例大家可以自己豐富下它的功能,看看效果。雞啄米謝謝大家的支持。

除非特別注明,雞啄米文章均為原創
轉載請標明本文地址:http://www.vkzldl.live/software/241.html
2012年9月22日
作者:雞啄米 分類:軟件開發 瀏覽: 評論:8