Skip Navigation Linksホーム > ライブラリ > ラベル > ラベルの背景を透過する

ラベルの背景を透過する

言語フィルタ:

概要

ラベルの背景を透過する方法を紹介します。

ラベルの背景を透過すると次のようになります。

sample1

対象コントロール

  • System.Windows.Forms.Label

解説

コントロールの背景を透過させるには「コントロールの背景を透過する」で紹介しているように、BackColor プロパティに Color.Transparent を設定します。しかし、この方法で透過された部分に表示されるのは親コントロールです。親コントロールとの間に別のコントロールがある場合でも、そのコントロールは表示されません(図1参照)。

図1
図1

別のコントロールが親コントロールとの間にある場合に、別のコントロールも表示されるように背景を透過するには Region プロパティを設定します。Region プロパティに背景以外の部分の領域を設定することでその部分だけが描画され、背景の部分は描画されずに透過されます。背景の部分は描画されないため半透明にすることはできません。

背景以外の部分の領域を取得するには、まず ClientSize プロパティと同じ大きさの Bitmap クラスを生成します。次に Bitmap クラスに文字列などの背景以外の部分を描画します。できた Bitmap クラスの全領域に対して描画された部分か否かを判定し、描画された部分だけの領域を作成します。描画された部分の判定にはアルファ値が 0 の場合を背景として判定しています。

展開されたイメージ 背景以外の領域の作成 - Visual Basic
コピーイメージ コードのコピー
' コントロールの ClientSize と同じ大きさの Bitmap クラスを生成します。
Dim foregroundBitmap As New Bitmap(Me.ClientSize.Width, Me.ClientSize.Height)

' 文字列などの背景以外の部分を描画します。
Using g As Graphics = Graphics.FromImage(foregroundBitmap)
    ' ここに文字列などの描画処理
End Using

Dim w As Integer = foregroundBitmap.Width
Dim h As Integer = foregroundBitmap.Height

Dim rect As New Rectangle(0, 0, w, h)
Dim region As New Region(rect)

' できた Bitmap クラスからピクセルの色情報を取得します。
Dim bd As BitmapData = foregroundBitmap.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb)
Dim stride As Integer = bd.Stride
Dim bytes As Integer = stride * h
Dim bgraValues As Byte() = New Byte(bytes - 1) {}
Marshal.Copy(bd.Scan0, bgraValues, 0, bytes)
foregroundBitmap.UnlockBits(bd)
foregroundBitmap.Dispose()

' 描画された部分だけの領域を作成します。
Dim line As Integer
For y As Integer = 0 To h - 1
    line = stride * y
    For x As Integer = 0 To w - 1
        ' アルファ値が 0 は背景
        If bgraValues(line + x * 4 + 3) = 0 Then
            region.Exclude(New Rectangle(x, y, 1, 1))
        End If
    Next
Next

' Region に描画された領域を設定します。
Me.Region = region
展開されたイメージ 背景以外の領域の作成 - C#
コピーイメージ コードのコピー
// コントロールの ClientSize と同じ大きさの Bitmap クラスを生成します。
Bitmap foregroundBitmap = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);

// 文字列などの背景以外の部分を描画します。
using (Graphics g = Graphics.FromImage(foregroundBitmap))
{
    this.DrawForeground(g);
}

int w = foregroundBitmap.Width;
int h = foregroundBitmap.Height;

Rectangle rect = new Rectangle(0, 0, w, h);
Region region = new Region(rect);

// できた Bitmap クラスからピクセルの色情報を取得します。
BitmapData bd = foregroundBitmap.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
int stride = bd.Stride;
int bytes = stride * h;
byte[] bgraValues = new byte[bytes];
Marshal.Copy(bd.Scan0, bgraValues, 0, bytes);
foregroundBitmap.UnlockBits(bd);
foregroundBitmap.Dispose();

// 描画された部分だけの領域を作成します。
int line;
for (int y = 0; y < h; y++)
{
    line = stride * y;
    for (int x = 0; x < w; x++)
    {
        // アルファ値が 0 は背景
        if (bgraValues[line + x * 4 + 3] == 0)
        {
            region.Exclude(new Rectangle(x, y, 1, 1));
        }
    }
}

// Region に描画された領域を設定します。
this.Region = region;

Region プロパティの設定に使用した Bitmap クラスと同じ内容を OnPaint メソッドで描画することで、背景以外の部分を描画することが出来ます。

Region プロパティを設定することにより、透過された背景の部分をクリックしても Click イベントは発生しません。代わりにクリックした位置に表示されているコントロールの Click イベントが発生します。

ソースコード

Label コントロールの背景を透過するサンプルを紹介します。

背景を透過するには BackColor プロパティに Color.Transparent を設定します。ただしデザイン時には完全に透過されません。実行時のみ透過されます。

OnTextChanged メソッドや OnSizeChanged メソッドなどの表示される文字列やコントロールのサイズが変更されるタイミングで Region プロパティを再設定してやる必要があります。UpdateRegion メソッドで Region プロパティを再設定しています。

展開されたイメージ Visual Basic
コピーイメージ コードのコピー
Imports System
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.Runtime.InteropServices
Imports System.Windows.Forms

Namespace Extentions

    Public Class TransparentLabel
        Inherits System.Windows.Forms.Label

        Private Sub UpdateRegion()
            ' コントロールの ClientSize と同じ大きさの Bitmap クラスを生成します。
            Dim foregroundBitmap As New Bitmap(Me.ClientSize.Width, Me.ClientSize.Height)

            ' 文字列などの背景以外の部分を描画します。
            Using g As Graphics = Graphics.FromImage(foregroundBitmap)
                Me.DrawForeground(g)
            End Using

            Dim w As Integer = foregroundBitmap.Width
            Dim h As Integer = foregroundBitmap.Height

            Dim rect As New Rectangle(0, 0, w, h)
            Dim region As New Region(rect)

            ' できた Bitmap クラスからピクセルの色情報を取得します。
            Dim bd As BitmapData = foregroundBitmap.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb)
            Dim stride As Integer = bd.Stride
            Dim bytes As Integer = stride * h
            Dim bgraValues As Byte() = New Byte(bytes - 1) {}
            Marshal.Copy(bd.Scan0, bgraValues, 0, bytes)
            foregroundBitmap.UnlockBits(bd)
            foregroundBitmap.Dispose()

            ' 描画された部分だけの領域を作成します。
            Dim line As Integer
            For y As Integer = 0 To h - 1
                line = stride * y
                For x As Integer = 0 To w - 1
                    ' アルファ値が 0 は背景
                    If bgraValues(line + x * 4 + 3) = 0 Then
                        region.Exclude(New Rectangle(x, y, 1, 1))
                    End If
                Next
            Next

            ' Region に描画された領域を設定します。
            Me.Region = region
        End Sub

        Private Sub DrawForeground(ByVal g As Graphics)
            Using sb As New SolidBrush(Me.ForeColor)
                Dim r As Rectangle = New Rectangle( _
                    Me.Padding.Left, _
                    Me.Padding.Top, _
                    Me.ClientRectangle.Width - Me.Padding.Left - Me.Padding.Right, _
                    Me.ClientRectangle.Height - Me.Padding.Top - Me.Padding.Bottom _
                )

                g.DrawString(Me.Text, Me.Font, sb, r)
            End Using
        End Sub

        Protected Overrides Sub OnTextChanged(ByVal e As System.EventArgs)
            If Me.DesignMode = False AndAlso Me.BackColor = Color.Transparent Then
                Me.UpdateRegion()
            End If

            MyBase.OnTextChanged(e)
        End Sub

        Protected Overrides Sub OnSizeChanged(ByVal e As System.EventArgs)
            If Me.DesignMode = False AndAlso Me.BackColor = Color.Transparent Then
                Me.UpdateRegion()
            End If

            MyBase.OnSizeChanged(e)
        End Sub

        Protected Overrides Sub OnPaddingChanged(ByVal e As System.EventArgs)
            If Me.DesignMode = False AndAlso Me.BackColor = Color.Transparent Then
                Me.UpdateRegion()
            End If

            MyBase.OnPaddingChanged(e)
        End Sub

        Protected Overrides Sub OnPaintBackground(ByVal pevent As System.Windows.Forms.PaintEventArgs)
            If Me.BackColor <> Color.Transparent Then
                MyBase.OnPaintBackground(pevent)
            Else
                If Me.DesignMode = True Then
                    MyBase.OnPaintBackground(pevent)
                End If
            End If
        End Sub

        Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
            If Me.BackColor <> Color.Transparent Then
                MyBase.OnPaint(e)
            Else
                ' UpdateRegion メソッドで描画したものと同じ内容を描画します
                Me.DrawForeground(e.Graphics)
            End If
        End Sub

    End Class

End Namespace
展開されたイメージ C#
コピーイメージ コードのコピー
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Extentions
{
    class TransparentLabel : System.Windows.Forms.Label
    {
        private void UpdateRegion()
        {
            // コントロールの ClientSize と同じ大きさの Bitmap クラスを生成します。
            Bitmap foregroundBitmap = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);

            // 文字列などの背景以外の部分を描画します。
            using (Graphics g = Graphics.FromImage(foregroundBitmap))
            {
                this.DrawForeground(g);
            }

            int w = foregroundBitmap.Width;
            int h = foregroundBitmap.Height;

            Rectangle rect = new Rectangle(0, 0, w, h);
            Region region = new Region(rect);

            // できた Bitmap クラスからピクセルの色情報を取得します。
            BitmapData bd = foregroundBitmap.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            int stride = bd.Stride;
            int bytes = stride * h;
            byte[] bgraValues = new byte[bytes];
            Marshal.Copy(bd.Scan0, bgraValues, 0, bytes);
            foregroundBitmap.UnlockBits(bd);
            foregroundBitmap.Dispose();

            // 描画された部分だけの領域を作成します。
            int line;
            for (int y = 0; y < h; y++)
            {
                line = stride * y;
                for (int x = 0; x < w; x++)
                {
                    // アルファ値が 0 は背景
                    if (bgraValues[line + x * 4 + 3] == 0)
                    {
                        region.Exclude(new Rectangle(x, y, 1, 1));
                    }
                }
            }

            // Region に描画された領域を設定します。
            this.Region = region;
        }

        private void DrawForeground(Graphics g)
        {
            using (SolidBrush sb = new SolidBrush(this.ForeColor))
            {
                Rectangle r = new Rectangle(
                    this.Padding.Left,
                    this.Padding.Top,
                    this.ClientRectangle.Width - this.Padding.Left - this.Padding.Right,
                    this.ClientRectangle.Height - this.Padding.Top - this.Padding.Bottom
                );

                g.DrawString(this.Text, this.Font, sb, r);
            }
        }

        protected override void OnTextChanged(EventArgs e)
        {
            if ((this.DesignMode == false) && (this.BackColor == Color.Transparent))
            {
                this.UpdateRegion();
            }
            base.OnTextChanged(e);
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            if ((this.DesignMode == false) && (this.BackColor == Color.Transparent))
            {
                this.UpdateRegion();
            }
            base.OnSizeChanged(e);
        }

        protected override void OnPaddingChanged(EventArgs e)
        {
            if ((this.DesignMode == false) && (this.BackColor == Color.Transparent))
            {
                this.UpdateRegion();
            }
            base.OnPaddingChanged(e);
        }

        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
            if (this.BackColor != Color.Transparent)
            {
                base.OnPaintBackground(pevent);
            }
            else
            {
                if (this.DesignMode == true)
                {
                    base.OnPaintBackground(pevent);
                }
            }
            base.OnPaintBackground(pevent);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            if (this.BackColor != Color.Transparent)
            {
                base.OnPaint(e);
            }
            else
            {
                // UpdateRegion メソッドで描画したものと同じ内容を描画します
                this.DrawForeground(e.Graphics);
            }
        }
    }
}