画像付きラベルを実現してみる

# 画像付きラベルを実現してみる

用途はともかく、テキストと画像がくっついた ように見える ラベルを作る方法を検討した。
諸般の事情でオーナードローなどの方法は、学んでる時間がとれないので検討から外す。

## 目標

テキストと画像を表示するラベル、をゴールに設定する。

- ラベルより大きな画像は適当な大きさに縮小できること。
- テキストと画像の位置を指定できること、ひとまず左右のみ。
- 長いテキストは折り返し表示して画像にかからない。
- ラベルには全体を囲う外枠 (Border) をつけられること。

## 実現方法

- できあがりサイズは、200 x 50 px、うち画像は 50 x 50 px とする。
- 画像は、プロジェクト (App.config が作られる) フォルダに適当な背景透明の png ファイルを置く。

### 設計時
![201702121755197249490.png](https://qiita-image-store.s3.amazonaws.com/0/93945/caf2e664-fa74-35d1-e781-6406d2022485.png)

### 実行時
![201702121751055014862.png](https://qiita-image-store.s3.amazonaws.com/0/93945/eaf84a1f-3d56-7d76-2341-023ff1deb1a0.png)

### その1: Label の上にそっと PictureBox を重ねる

できあがりサイズの Label を用意して、その右端に PictureBox を「置く」。
外枠線を実現するために、Label の内部に PictureBox が位置づけられるようにしている。

最初に思いつく方式、単純。移動は両コントロールの Location で制御。煩雑だが、初学者にも直感的に理解できる。背景色を指定する場合なども両コントロールの背景色を設定する必要がある。
ただし、この弱点は、ユーザーコントロールに閉じ込めてしまえば、利用側は気にする必要はなくなるかもしれない。

```csharp
private void Form1_Load(object sender, EventArgs e)
{
    // その1
    label1.BackColor = SystemColors.ActiveCaption;
    label1.Size = new Size(200, 50);
    label1.Text = "label1label1label1label1label1label1label1label1";
    label1.BorderStyle = BorderStyle.FixedSingle;
    pictureBox1.Size = new Size(48, 48);
    pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
    pictureBox1.BackColor = SystemColors.ActiveCaption;
    pictureBox1.PictureBox = Image.FromFile("../../sample.png");
}
```

### その2 Label を PictureBox の子コントロールとして配置する

Label を PictureBox の子コントロールにする。これも、素直な手。Padding プロパティを使って画像を右端に追いやる。
画像を左に置く場合は同じく Padding プロパティと、Label の Location で調整する。
PictureBox と Label だけで構成できるのが好感できる。

```csharp
private void Form1_Load(object sender, EventArgs e)
{
    // その2
    label2.BackColor = Color.Transparent;
    label2.Parent = pictureBox2;
    label2.Location = Point.Empty;
    label2.Size = new Size(148, 48);
    label2.Text = "label2label2label2label2label2label2label2label2";
    pictureBox2.BorderStyle = BorderStyle.FixedSingle;
    pictureBox2.Size = new Size(200, 50);
    pictureBox2.SizeMode = PictureBoxSizeMode.StretchImage;
    pictureBox2.BackColor = SystemColors.ActiveCaption;
    pictureBox2.Padding = new Padding(150, 0, 0, 0);
    pictureBox2.PictureBox = Image.FromFile("../../sample.png");
    pictureBox2.Controls.Add(label2);
}
```

### その3 !NG! Label に PictureBox と Text を設定する

「テキストが画像にかからない」という点で目標を満たせない。Padding プロパティがイメージとテキストの両方に効くので重なってしまう。

```csharp
private void Form1_Load(object sender, EventArgs e)
{
    // その3
    var PictureBox = Image.FromFile("../../sample.png");
    var canvas = new Bitmap(48, 48);
    using (var g = Graphics.FromImage(canvas))
    {
        g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
        g.DrawImage(image, 0, 0, 48, 48);
        image.Dispose();
    }
    label3.BorderStyle = BorderStyle.FixedSingle;
    label3.Size = new Size(200, 50);
    label3.PictureBox = canvas;
    label3.TextAlign = ContentAlignment.TopLeft;
    label3.ImageAlign = ContentAlignment.MiddleRight;
    label3.BackColor = SystemColors.ActiveCaption;
    label3.Text = "label3label3label3label3label3label3label3label3";
}
```

### その4 レイアウトパネルに Label と PictureBox を配置する

もう少し複雑なレイアウト要求が出てきそうなら、FlowLayOutPanel や TableLayoutPanel などに配置した方がよくなるかもしれない。

```csharp
private void Form1_Load(object sender, EventArgs e)
{
    // その4
    flowLayoutPanel4.BorderStyle = BorderStyle.FixedSingle;
    flowLayoutPanel4.Size = new Size(200, 50);
    flowLayoutPanel4.Controls.Add(label4);
    flowLayoutPanel4.Controls.Add(pictureBox4);
    flowLayoutPanel4.BackColor = SystemColors.ActiveCaption;
    label4.BackColor = Color.Transparent;
    label4.Size = new Size(148, 48);
    label4.Text = "label4label4label4label4label4label4label4label4";
    pictureBox4.Size = new Size(48, 48);
    pictureBox4.BackColor = Color.Transparent;
    pictureBox4.PictureBox = Image.FromFile("../../sample.png");
}
```

## 確認した環境

- OS: 日本語 Windows 10 Home 64ビット
- コンパイラ: Visual Studio Community 2017 RC