言語フィルタ:
概要
ラベルの背景を透過する方法を紹介します。
ラベルの背景を透過すると次のようになります。
対象コントロール
- System.Windows.Forms.Label
解説
コントロールの背景を透過させるには「コントロールの背景を透過する」で紹介しているように、BackColor プロパティに Color.Transparent を設定します。しかし、この方法で透過された部分に表示されるのは親コントロールです。親コントロールとの間に別のコントロールがある場合でも、そのコントロールは表示されません(図1参照)。
| 図1 |
 |
別のコントロールが親コントロールとの間にある場合に、別のコントロールも表示されるように背景を透過するには Region プロパティを設定します。Region プロパティに背景以外の部分の領域を設定することでその部分だけが描画され、背景の部分は描画されずに透過されます。背景の部分は描画されないため半透明にすることはできません。
背景以外の部分の領域を取得するには、まず ClientSize プロパティと同じ大きさの Bitmap クラスを生成します。次に Bitmap クラスに文字列などの背景以外の部分を描画します。できた Bitmap クラスの全領域に対して描画された部分か否かを判定し、描画された部分だけの領域を作成します。描画された部分の判定にはアルファ値が 0 の場合を背景として判定しています。
' コントロールの 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
// コントロールの 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 プロパティを再設定しています。
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
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);
}
}
}
}