Share via


在同一行上繪製不同字型的文字

字型系列中的不同類型樣式可以有不同的寬度。 例如,系列粗體和斜體樣式一律比指定點大小的羅馬樣式寬。 當您在單行上顯示或列印數種類型樣式時,必須追蹤線條的寬度,以避免在彼此上方顯示或列印字元。

您可以使用兩個函式來擷取目前字型中文字的寬度 (或範圍) 。 GetTabbedTextExtent函式會計算字元字串的寬度和高度。 如果字串包含一或多個定位字元,字串的寬度會以指定的定位停駐點位置陣列為基礎。 GetTextExtentPoint32函式會計算文字行的寬度和高度。

必要時,系統會藉由變更字元點陣圖來合成字型。 若要以粗體字型合成字元,系統會在起始點繪製字元兩次:在起點,然後再次繪製起點右邊的一個圖元。 為了在斜體字型中合成字元,系統會在字元資料格底部繪製兩列圖元、將起點移到右邊一個圖元、繪製下兩個數據列,然後繼續直到繪製字元為止。 藉由將圖元移位,每個字元似乎會向右傾斜。 切割量是字元高度的函式。

撰寫包含多個字型的文字行的其中一種方式,是在每次呼叫TextOut之後使用GetTextExtentPoint32函式,並將長度新增至目前位置。 下列範例會寫入 「This is a sample string」 這一行。使用粗體字元 「This is a」,切換為 「sample」 的斜體字元,然後傳回 「string」 的粗體字元。列印所有字串之後,它會還原系統預設字元。

int XIncrement; 
int YStart; 
TEXTMETRIC tm; 
HFONT hfntDefault, hfntItalic, hfntBold; 
SIZE sz; 
LPSTR lpszString1 = "This is a "; 
LPSTR lpszString2 = "sample "; 
LPSTR lpszString3 = "string."; 
HRESULT hr;
size_t * pcch;
 
// Create a bold and an italic logical font.  
 
hfntItalic = MyCreateFont(); 
hfntBold = MyCreateFont(); 
 
 
// Select the bold font and draw the first string  
// beginning at the specified point (XIncrement, YStart).  
 
XIncrement = 10; 
YStart = 50; 
hfntDefault = SelectObject(hdc, hfntBold); 
hr = StringCchLength(lpszString1, 11, pcch);
        if (FAILED(hr))
        {
        // TODO: write error handler 
        }
TextOut(hdc, XIncrement, YStart, lpszString1, *pcch); 
 
// Compute the length of the first string and add  
// this value to the x-increment that is used for the  
// text-output operation.  

hr = StringCchLength(lpszString1, 11, pcch);
        if (FAILED(hr))
        {
        // TODO: write error handler 
        } 
GetTextExtentPoint32(hdc, lpszString1, *pcch, &sz); 
XIncrement += sz.cx; 
 
// Retrieve the overhang value from the TEXTMETRIC  
// structure and subtract it from the x-increment.  
// (This is only necessary for non-TrueType raster  
// fonts.)  
 
GetTextMetrics(hdc, &tm); 
XIncrement -= tm.tmOverhang; 
 
// Select an italic font and draw the second string  
// beginning at the point (XIncrement, YStart).  
 
hfntBold = SelectObject(hdc, hfntItalic); 
GetTextMetrics(hdc, &tm); 
XIncrement -= tm.tmOverhang;
hr = StringCchLength(lpszString2, 8, pcch);
        if (FAILED(hr))
        {
        // TODO: write error handler 
        } 
TextOut(hdc, XIncrement, YStart, lpszString2, *pcch); 
 
// Compute the length of the second string and add  
// this value to the x-increment that is used for the  
// text-output operation.  

hr = StringCchLength(lpszString2, 8, pcch);
        if (FAILED(hr))
        {
        // TODO: write error handler 
        }  
GetTextExtentPoint32(hdc, lpszString2, *pcch, &sz); 
XIncrement += sz.cx; 
 
// Reselect the bold font and draw the third string  
// beginning at the point (XIncrement, YStart).  
 
SelectObject(hdc, hfntBold);
hr = StringCchLength(lpszString3, 8, pcch);
        if (FAILED(hr))
        {
        // TODO: write error handler 
        }  
TextOut(hdc, XIncrement - tm.tmOverhang, YStart, lpszString3, 
            *pcch); 
 
// Reselect the original font.  
 
SelectObject(hdc, hfntDefault); 
 
// Delete the bold and italic fonts.  
 
DeleteObject(hfntItalic); 
DeleteObject(hfntBold); 

在此範例中, GetTextExtentPoint32 函式會使用指定字串的長度和高度,初始化 SIZE 結構的成員。 GetTextMetrics函式會擷取目前字型的加號。 因為如果字型是 TrueType 字型,則過度交集值不會變更字串放置。 不過,對於點陣字型而言,請務必使用暫存值。

如果字型是點陣字型,則會從粗體字串減去一次粗體字串,讓後續字元更接近字串結尾。 因為過度停留會影響點陣字型中斜體字串的開頭和結尾,所以字元會從指定位置的右邊開始,並在最後一個字元儲存格的端點左邊結束。 (GetTextExtentPoint32 函式會擷取字元資料格的範圍,而不是字元的範圍。) 為了考慮點陣斜體字串中的暫留,此範例會在放置字串之前先減去加號,然後再放下後續字元再減去它。

SetTextJustification函式會將額外的空間新增至一行文字中的中斷字元。 您可以使用 GetTextExtentPoint 函式來判斷字串的範圍,然後從行應佔用的空間總量減去該範圍,並使用 SetTextJustification 函式在字串中的中斷字元之間分配額外的空間。 SetTextCharacterExtra函式會將額外的空間新增至所選字型中的每個字元儲存格,包括中斷字元。 (您可以使用 GetTextCharacterExtra 函式來判斷新增至字元儲存格的目前額外空間量;預設設定為零。)

您可以使用 GetCharWidth32GetCharABCWidths 函式來擷取字型中個別字元的寬度,以更精確地放置字元。 GetCharABCWidths函式比GetCharWidth32函式更精確,但只能搭配 TrueType 字型使用。

ABC 間距也可讓應用程式執行非常精確的文字對齊。 例如,當應用程式靠右對齊點陣羅馬字型而不使用 ABC 間距時,進階寬度會計算為字元寬度。 這表示點陣圖中圖像右邊的空白字元對齊,而不是圖像本身。 藉由使用 ABC 寬度,應用程式在對齊文字時,在放置和移除空白字元時具有更大的彈性,因為它們具有可讓它們精細控制字元間距的資訊。