TextRenderer で描画する文字列をクリップする - C#

TextRenderer で描画する文字列をクリップするコードを紹介します。

概要

TextRenderer で描画する文字列をクリップするには、boundsパラメーターにクリップする範囲を指定します。

プログラム例

UI

下図のフォームを作成します。Panelを一つ配置します。

コード:背景を描画するのみ

以下のコードを記述します。背景色を描画するのみのコードです。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TextRendererDemo
{
  public partial class FormTextRendererClip : Form
  {
    public FormTextRendererClip()
    {
      InitializeComponent();
    }

    private void panel1_Paint(object sender, PaintEventArgs e)
    {
      SolidBrush sbk = new SolidBrush(Color.FromArgb(0xA0, 0xA0, 0xA0));
      e.Graphics.FillRectangle(sbk, new Rectangle(0, 0, panel1.Width, panel1.Height));

      SolidBrush sb = new SolidBrush(Color.FromArgb(0x00, 0x77, 0xe6));
      e.Graphics.FillRectangle(sb,new Rectangle(128,48,360,96));
    }
  }
}

実行結果

実行すると下図のウィンドウが表示されます。背景部分に着色されます。
今回は青の部分の領域でテキストをクリップして描画したいです。

コード:単純なTextRendererの描画

描画位置の座標のみを指定してTextRendererで描画します。下記のコードに変更します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TextRendererDemo
{
  public partial class FormTextRendererClip : Form
  {
    public FormTextRendererClip()
    {
      InitializeComponent();
    }

    private void panel1_Paint(object sender, PaintEventArgs e)
    {
      SolidBrush sbk = new SolidBrush(Color.FromArgb(0xA0, 0xA0, 0xA0));
      e.Graphics.FillRectangle(sbk, new Rectangle(0, 0, panel1.Width, panel1.Height));

      SolidBrush sb = new SolidBrush(Color.FromArgb(0x00, 0x77, 0xe6));
      e.Graphics.FillRectangle(sb,new Rectangle(128,48,360,96));
      
      string Drawtext = "ぺんぎんクッキー";
      Font f = new Font("Yu Gothic UI", 48);
      TextRenderer.DrawText(e.Graphics, Drawtext, f, new Point(128, 88), Color.White);
    }
  }
}

実行結果

プロジェクトを実行します。下図のウィンドウが表示されます。テキストが描画されますが、あお枠の外側にも描画されています。

コード:boundsパラメーターを指定した描画

以下のコードに変更し、TextRendererのDrawTextメソッドにboundsパラメーターを指定します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TextRendererDemo
{
  public partial class FormTextRendererClip : Form
  {
    public FormTextRendererClip()
    {
      InitializeComponent();
    }

    private void panel1_Paint(object sender, PaintEventArgs e)
    {
      SolidBrush sbk = new SolidBrush(Color.FromArgb(0xA0, 0xA0, 0xA0));
      e.Graphics.FillRectangle(sbk, new Rectangle(0, 0, panel1.Width, panel1.Height));

      Rectangle Area = new Rectangle(128, 48, 360, 96);
      SolidBrush sb = new SolidBrush(Color.FromArgb(0x00, 0x77, 0xe6));
      e.Graphics.FillRectangle(sb, Area);
      
      string Drawtext = "ぺんぎんクッキー";
      Font f = new Font("Yu Gothic UI", 48);

      Rectangle DrawRect = new Rectangle(128, 88, 10000, 10000);
      Rectangle ClipArea = Rectangle.Intersect(DrawRect, Area);

      TextRenderer.DrawText(e.Graphics, Drawtext, f, ClipArea, Color.White);
    }
  }
}

解説

青い枠を描画するRectangleオブジェクトを変数に格納します。
  Rectangle Area = new Rectangle(128, 48, 360, 96);

テキストを描画するRectangleを用意します。左上の開始位置のみを指定し、幅と高さは十分大きい値を設定しておきます。
  Rectangle DrawRect = new Rectangle(128, 88, 10000, 10000);

Intersectメソッドを利用して、青枠の領域と、テキストを描画する領域の共通部分のRectangleを求めます。 Intersectメソッドの動作の詳細はこちらの記事を参照して下さい。
  Rectangle ClipArea = Rectangle.Intersect(DrawRect, Area);

実行結果

プロジェクトを実行すると下図の画面が表示されます。青枠内でテキストがクリップされて描画できています。
ただし、クリップを指定しなかった場合と比べると、描画開始の位置が左にずれています。
これは、boundsパラメーターを指定した場合は、デフォルトでは、TextFormatFlags.HorizontalCenter フラグが適用されるためだと考えられます。

コード:TextFormatFlags パラメーターを指定する場合

TextFormatFlags パラメーターを指定して左寄せで描画します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TextRendererDemo
{
  public partial class FormTextRendererClip : Form
  {
    public FormTextRendererClip()
    {
      InitializeComponent();
    }

    private void panel1_Paint(object sender, PaintEventArgs e)
    {
      SolidBrush sbk = new SolidBrush(Color.FromArgb(0xA0, 0xA0, 0xA0));
      e.Graphics.FillRectangle(sbk, new Rectangle(0, 0, panel1.Width, panel1.Height));

      Rectangle Area = new Rectangle(128, 48, 360, 96);
      SolidBrush sb = new SolidBrush(Color.FromArgb(0x00, 0x77, 0xe6));
      e.Graphics.FillRectangle(sb, Area);
      
      string Drawtext = "ぺんぎんクッキー";
      Font f = new Font("Yu Gothic UI", 48);

      Rectangle DrawRect = new Rectangle(128, 88, 10000, 10000);
      Rectangle ClipArea = Rectangle.Intersect(DrawRect, Area);

      TextRenderer.DrawText(e.Graphics, Drawtext, f, ClipArea, Color.White,TextFormatFlags.Default);

    }
  }
}

解説

TextFormatFlags.Defaultを指定します。
  TextRenderer.DrawText(e.Graphics, Drawtext, f, ClipArea, Color.White,TextFormatFlags.Default);

実行結果

下図の結果となります。bounds パラメータを指定しなかった場合と同様の位置で、青枠のエリアでクリップされてテキストが描画されています。

プログラム例:GraphicsオブジェクトのSetClipを利用する例

メモ
クリップされて描画できない場合は、Graphicsオブジェクトでクリップされている場合があります。その際は、TextFormatFlags.PreserveGraphicsClipping フラグを追加します。

TextRenderer.DrawText(e.Graphics, Drawtext, f, ClipArea,
  Color.White,TextFormatFlags.Default | TextFormatFlags.PreserveGraphicsClipping);

UI

下図のフォームを作成します。Panelを一つ配置します。

コード

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TextRendererDemo
{
  public partial class FormTextRendererClip2 : Form
  {
    public FormTextRendererClip2()
    {
      InitializeComponent();
    }

    private void panel1_Paint(object sender, PaintEventArgs e)
    {
      Rectangle frame = new Rectangle(64, 32, 240, 96);

      Pen p = new Pen(Color.FromArgb(0x41, 0x93, 0xf8),2);
      e.Graphics.DrawRectangle(p, frame);

      e.Graphics.SetClip(frame);
      e.Graphics.DrawLine(p, new Point(128, 0), new Point(512, 256));

      string drawText = "Penguin Cookie";

      Rectangle textArea = new Rectangle(64, 72, 512, 512);
      Font f = new Font("Yu Gothic UI",48);
      TextRenderer.DrawText(e.Graphics, drawText, f, textArea, Color.FromArgb(0x5e,0xa5,0x45),TextFormatFlags.Default);

      e.Graphics.ResetClip();
    }
  }
}

解説

四角形の枠を描画します。
      Rectangle frame = new Rectangle(64, 32, 240, 96);

      Pen p = new Pen(Color.FromArgb(0x41, 0x93, 0xf8),2);
      e.Graphics.DrawRectangle(p, frame);

描画した四角形の大きさでクリップします。Graphicsオブジェクトのクリップについてはこちらの記事を参照してください。
      e.Graphics.SetClip(frame);

クリップされた状態で線を描画します。
      e.Graphics.DrawLine(p, new Point(128, 0), new Point(512, 256));

TextRendererでテキストを描画します。
      string drawText = "Penguin Cookie";

      Rectangle textArea = new Rectangle(64, 72, 512, 512);
      Font f = new Font("Yu Gothic UI",48);
      TextRenderer.DrawText(e.Graphics, drawText, f, textArea, Color.FromArgb(0x5e,0xa5,0x45),TextFormatFlags.Default);

クリップを解除します。
      e.Graphics.ResetClip();

実行結果

実行します。下図の画面が表示されます。クリップされないことが確認できます。

コードの修正

以下のコードに変更します。
private void panel1_Paint(object sender, PaintEventArgs e)
{
  Rectangle frame = new Rectangle(64, 32, 240, 96);

  Pen p = new Pen(Color.FromArgb(0x41, 0x93, 0xf8),2);
  e.Graphics.DrawRectangle(p, frame);

  e.Graphics.SetClip(frame);
  e.Graphics.DrawLine(p, new Point(128, 0), new Point(512, 256));

  string drawText = "Penguin Cookie";

  Rectangle textArea = new Rectangle(64, 72, 512, 512);
  Font f = new Font("Yu Gothic UI",48);
  TextRenderer.DrawText(e.Graphics, drawText, f, textArea, Color.FromArgb(0x5e, 0xa5, 0x45), TextFormatFlags.Default | TextFormatFlags.PreserveGraphicsClipping);

  e.Graphics.ResetClip();
}

実行結果

実行します。下図の画面が表示されます。クリップされて描画されます。


著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
掲載日: 2023-01-18
iPentec all rights reserverd.