首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# GDI+ 繪製垂直文字:座標轉換法與 StringFormat 一行解決

     編輯:關於C語言

前言

在圖表 Y 軸標籤、直式排版、印刷預覽等場景需繪製垂直文字。本文對比兩種做法:傳統座標變換(平移→旋轉→平移)與現代 StringFormatFlags.DirectionVertical 一行解決。

方法一:傳統座標變換 (適用所有 .NET 版本)


using System.Drawing;
using System.Drawing.Drawing2D;

public void DrawVerticalTextLegacy(Graphics g, string text, Font font, Brush brush, float x, float y)
{
    // 1. 儲存當前變換狀態
    GraphicsState state = g.Save();
    
    try
    {
        // 2. 將原點移至旋轉中心 (文字中心點)
        g.TranslateTransform(x, y);
        
        // 3. 逆時針旋轉 90 度 (或 270 度順時針)
        g.RotateTransform(-90); // -90 = 逆時針 90 度
        
        // 4. 繪製文字 (現原點為旋轉中心)
        g.DrawString(text, font, brush, 0, 0);
    }
    finally
    {
        // 5. 恢復原始變換 (關鍵:避免影響後續繪圖)
        g.Restore(state);
    }
}

// 使用範例:Y 軸標籤
public void DrawYAxisLabels(Graphics g, Rectangle plotArea)
{
    using (Font font = new Font("Microsoft JhengHei", 10))
    using (Brush brush = Brushes.Black)
    {
        for (int i = 0; i <= 100; i += 10)
        {
            float y = plotArea.Bottom - (i / 100f) * plotArea.Height;
            string label = i.ToString();
            
            // 計算文字大小以置中
            SizeF textSize = g.MeasureString(label, font);
            float x = plotArea.Left - textSize.Height - 5; // 左側留白
            
            DrawVerticalTextLegacy(g, label, font, brush, x, y);
        }
    }
}

座標變換原理圖解

原始座標系:          旋轉後座標系:
Y ↑                  X' ↑ (原 -Y 方向)
 |                   |
 +--→ X              +--→ Y' (原 X 方向)

步驟:
1. Translate(x, y)  : 原點移到 (x,y)
2. Rotate(-90)      : 座標系逆時針轉 90°
3. DrawString(0,0)  : 在新原點繪製
4. Restore()        : 還原座標系

方法二:StringFormat.DirectionVertical (一行代碼,.NET Framework 4.5+ / .NET Core 3.0+)


public void DrawVerticalTextModern(Graphics g, string text, Font font, Brush brush, float x, float y)
{
    // 關鍵:StringFormatFlags.DirectionVertical
    var format = new StringFormat(StringFormatFlags.DirectionVertical)
    {
        Alignment = StringAlignment.Center,   // 水平置中 (旋轉後為垂直置中)
        LineAlignment = StringAlignment.Center // 垂直置中 (旋轉後為水平置中)
    };
    
    // 直接在指定位置繪製,GDI+ 內部處理旋轉
    g.DrawString(text, font, brush, x, y, format);
}

// 更簡潔的單行版
g.DrawString(text, font, brush, x, y, new StringFormat(StringFormatFlags.DirectionVertical));

完整範例:繪製帶垂直 Y 軸標籤的圖表


public void DrawChartWithVerticalLabels(Graphics g, Rectangle clientRect)
{
    var plotArea = new Rectangle(80, 40, clientRect.Width - 100, clientRect.Height - 80);
    
    // 1. 繪製座標軸
    using (var axisPen = new Pen(Color.Black, 2))
    {
        g.DrawLine(axisPen, plotArea.Left, plotArea.Bottom, plotArea.Right, plotArea.Bottom); // X 軸
        g.DrawLine(axisPen, plotArea.Left, plotArea.Top, plotArea.Left, plotArea.Bottom);     // Y 軸
    }
    
    // 2. 繪製垂直 Y 軸標籤 (現代方法)
    using (Font font = new Font("Microsoft JhengHei", 9))
    using (Brush brush = Brushes.DarkBlue)
    {
        for (int i = 0; i <= 10; i++)
        {
            float y = plotArea.Bottom - (i / 10f) * plotArea.Height;
            string label = $"{i * 10}%";
            
            // 文字區域在 Y 軸左側
            float x = plotArea.Left - 50;
            
            g.DrawString(label, font, brush, x, y, 
                new StringFormat(StringFormatFlags.DirectionVertical)
                {
                    Alignment = StringAlignment.Center,
                    LineAlignment = StringAlignment.Center
                });
        }
    }
    
    // 3. 繪製水平 X 軸標籤 (對比)
    using (Font font = new Font("Microsoft JhengHei", 9))
    using (Brush brush = Brushes.DarkBlue)
    {
        for (int i = 0; i <= 10; i++)
        {
            float x = plotArea.Left + (i / 10f) * plotArea.Width;
            string label = $"{i * 10}";
            
            g.DrawString(label, font, brush, x, plotArea.Bottom + 5,
                new StringFormat { Alignment = StringAlignment.Center });
        }
    }
}

關鍵差異對比

特性座標變換法StringFormat.Vertical
代碼複雜度高 (Save/Translate/Rotate/Restore)極低 (一行)
相容性所有 .NET 版本.NET Framework 4.5+ / .NET Core 3.0+
效能稍高 (矩陣運算)內部優化,略快
文字度量MeasureString 需在變換後座標系正常 MeasureString 即可
對齊控制手動計算StringFormat Alignment/LineAlignment
字型回退正常部分舊版字型可能不支援垂直排版

注意事項與坑點

  • Compact Framework / .NET Micro Framework:不支援 DirectionVertical,必須用座標變換
  • 字型支援:中文字型需支援垂直排版 (OpenType `vert` 特性),微軟正黑體、新細明體支援良好
  • 度量陷阱:MeasureString 回傳寬高在原始座標系,垂直文字實際佔用區域為 (Height, Width)
  • 抗鋸齒:設定 g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit 獲得最佳品質
  • Right-to-Left 語言:阿拉伯文/希伯來文垂直排版行為不同,需實測

WPF / UWP / WinUI 3 現代做法




    
        
    


總結

現代專案請直接使用 StringFormatFlags.DirectionVertical,代碼簡潔、可維護、效能佳。僅在舊版 .NET CF、特殊字型相容性場景才需手動座標變換。理解兩者原理有助於除錯複雜排版問題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved