web-dev-qa-db-ja.com

透明なボタンを描く

WinFormsアプリケーションで使用する透明なボタンをC#(.NET 3.5 SP1)で作成しようとしています。ボタンを透明にするためにあらゆることを試しました(ボタンの下にグラデーションの背景が表示されるはずです)が、機能しません。

これが私が使っているコードです:

public class ImageButton : ButtonBase, IButtonControl
{
    public ImageButton()
    {
        this.SetStyle(
            ControlStyles.SupportsTransparentBackColor | 
            ControlStyles.OptimizedDoubleBuffer | 
            ControlStyles.AllPaintingInWmPaint | 
            ControlStyles.ResizeRedraw | 
            ControlStyles.UserPaint, true);
        this.BackColor = Color.Transparent;
    }

    protected override void OnPaint(PaintEventArgs pevent)
    {
        Graphics g = pevent.Graphics;
        g.FillRectangle(Brushes.Transparent, this.ClientRectangle);
        g.DrawRectangle(Pens.Black, this.ClientRectangle);
    }


    // rest of class here...

}

問題は、ボタンがどこかからランダムなUIメモリを取得し、Visual StudioのUI(デザインモードの場合)からいくつかのバッファーで自分自身を埋めているように見えることです。実行時にそれはいくつかのゼロのバッファをつかんでいて、完全に黒です。

私の最終的な目標は、長方形ではなく非表示のボタンに画像をペイントすることです。ただし、コンセプトは変わらないはずです。ユーザーがボタンの上にカーソルを置くと、ボタンタイプの形状が描画されます。

何か案は?

編集:みんなありがとう、以下が私のために働いた:

public class ImageButton : Control, IButtonControl
{
    public ImageButton()
    {
        SetStyle(ControlStyles.SupportsTransparentBackColor, true);
        SetStyle(ControlStyles.Opaque, true);
        SetStyle(ControlStyles.ResizeRedraw, true);
        this.BackColor = Color.Transparent;

    }

    protected override void OnPaint(PaintEventArgs pevent)
    {
        Graphics g = pevent.Graphics;
        g.DrawRectangle(Pens.Black, this.ClientRectangle);
    }


    protected override void OnPaintBackground(PaintEventArgs pevent)
    {
        // don't call the base class
        //base.OnPaintBackground(pevent);
    }


    protected override CreateParams CreateParams
    {
        get
        {
            const int WS_EX_TRANSPARENT = 0x20;
            CreateParams cp = base.CreateParams;
            cp.ExStyle |= WS_EX_TRANSPARENT;
            return cp;
        }
    }

    // rest of class here...
}
21
rein

WinForms(および基盤となるUser32)は透明性をまったくサポートしていません。ただし、WinFormsは、指定したコントロールスタイル(SupportsTransparentBackColor)を使用して透明度をシミュレートできますが、この場合、「透明」コントロールが行うすべての操作で、親の背景を描画できます。

ButtonBaseは、このメカニズムの動作を妨げるいくつかのウィンドウスタイルを使用します。 2つの解決策があります。1つは(ButtonBaseではなく)Controlからコントロールを派生させることで、もう1つは親のDrawToBitmapを使用してボタンの下に背景を取得し、この画像をOnPaintで描画することです。

16
arbiter

Winformsには、透明度を使用するときにコントロールの背景を正しくペイントできるようにするいくつかのトリックがあります。このコードをOnPaintまたはOnPaintBackgroundに追加して、ペイントされている背景にあるコントロールを取得できます。

if (this.Parent != null)
{
 GraphicsContainer cstate = pevent.Graphics.BeginContainer();
 pevent.Graphics.TranslateTransform(-this.Left, -this.Top);
 Rectangle clip = pevent.ClipRectangle;
 clip.Offset(this.Left, this.Top);
 PaintEventArgs pe = new PaintEventArgs(pevent.Graphics, clip);

 //Paint the container's bg
 InvokePaintBackground(this.Parent, pe);
 //paints the container fg
 InvokePaint(this.Parent, pe);
 //restores graphics to its original state
 pevent.Graphics.EndContainer(cstate);
}
else
  base.OnPaintBackground(pevent); // or base.OnPaint(pevent);...
10
jmservera

ButtonBaseが透明度をサポートしているのかわかりません...それを確認しましたか?

多くの透過的なコントロールを作成しましたが、常にControlまたはUserControlから継承しています。

コントロールの描画をブロックする場合は、その背景です。OnPaintではなくOnPaintBackgroundをオーバーライドし、基本クラスを呼び出さないでください。

しかし、Brushes.Transparentで長方形を塗りつぶすのはおかしいです。または別の言い方をすると、何もしません!

1
Dan Byström

私はこの質問が古いことを知っていますが、誰かがこれを行うためのコントロールを作成したくない場合は、別の記事からこのコードを考え出し、拡張メソッドを変更しました。

public static void ToTransparent(this System.Windows.Forms.Button Button,
     System.Drawing.Color TransparentColor)
{
    Bitmap bmp = ((Bitmap)Button.Image);
    bmp.MakeTransparent(TransparentColor);
    int x = (Button.Width - bmp.Width) / 2;
    int y = (Button.Height - bmp.Height) / 2;
    Graphics gr = Button.CreateGraphics();
    gr.DrawImage(bmp, x, y);
}

そして、次のような呼び出し:

buttonUpdate.ToTransparent(Color.Magenta);
1
Kevin