C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[6]: 半透明のラベル


(過去ログ 125 を表示中)

[トピック内 7 記事 (1 - 7 表示)]  << 0 >>

■74588 / inTopicNo.1)  半透明のラベル
  
□投稿者/ ソースハンター (1回)-(2015/01/10(Sat) 20:09:40)

分類:[C#] 

開発環境 VS C#Express2010 .Net4.0 Windows7 Home

PictrueBoxの上に文字列を描画できる半透明のコントロールを用意したいです。
PictrueBoxと同じ大きさにします。薄い色を付けてカバーみたいにしたいです。

Labelをカスタムすればいけるのかもしれませんが、いい方法がわかりません。
どのようにすればいいのでしょうか。
引用返信 編集キー/
■74589 / inTopicNo.2)  Re[1]: 半透明のラベル
□投稿者/ Azulean (403回)-(2015/01/10(Sat) 21:42:22)
2015/01/10(Sat) 21:44:18 編集(投稿者)
No74588 (ソースハンター さん) に返信
> PictrueBoxの上に文字列を描画できる半透明のコントロールを用意したいです。
> PictrueBoxと同じ大きさにします。薄い色を付けてカバーみたいにしたいです。

背景色を半透明にした重ね合わせを実現したいということですが、コントロールであるところまで求めますか?

たとえば、PictureBox の Paint イベントでα値をつけて全面を塗って、その後に文字列を描くと言うことでも半透明の重ね合わせはできます。
もし、コントロールとして独立させるのであれば、Label クラスを継承して OnPaintBackground あたりをオーバーライドして工夫することになりそうです。


殴り書きレベル。テスト不十分。
public class LabelEx : Label
{
    [DefaultValue(1.0)]
    public double Opacity { get; set; }

    public new Color BackColor { get; set; }

    public LabelEx()
    {
        base.BackColor = Color.Transparent;
        Opacity = 1.0;
    }

    protected override void OnPaintBackground(PaintEventArgs e)
    {
        base.OnPaintBackground(e);
        int alpha = Math.Min(Math.Max((int)Math.Round(255 * Opacity), 0), 255);
        using (var brush = new SolidBrush(Color.FromArgb(alpha, BackColor)))
        {
            e.Graphics.FillRectangle(brush, ClientRectangle);
        }
    }
}

// 親コントロールの背景を描かせる処理を書くのを端折りたかったので基底クラスの処理をTransparentで呼んでごまかしています。


追伸
元の Label コントロールもそうですが、PictrureBox の子コントロールにしていない場合、Form の背景が表示されます。
必要なら PictureBox.Controls.Add(labelEx1); といったように親コントロールを変更するか、
PictureBox ではなく、Panel を使ってください。

引用返信 編集キー/
■74590 / inTopicNo.3)  Re[2]: 半透明のラベル
□投稿者/ ソースハンター (2回)-(2015/01/10(Sat) 23:53:40)
なるほどありがとうございます。
確かに今後の事を考えるとPicutrueBoxを改造したほうがよさそうですね。

    public partial class CustomControl2 : PictureBox
    {
        [DefaultValue(1.0)]
        public double Opacity { get; set; }

        public new Color BackColor { get; set; }

        [DefaultValue("")]
        public string strTest { get; set; }

        public CustomControl2()
        {
            InitializeComponent();
            strTest = "0";
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            base.OnPaint(pe);

            int alpha = Math.Min(Math.Max((int)Math.Round(255 * Opacity), 0), 255);
            using (var brush = new SolidBrush(Color.FromArgb(alpha, BackColor)))
            {
                pe.Graphics.FillRectangle(brush, ClientRectangle);
            }

            using (var brush = new SolidBrush(Color.PaleVioletRed))
            {
                pe.Graphics.DrawString(strTest, new System.Drawing.Font("MS UI Gothic", 20), brush, new PointF(10, 10));
            }

        }
    }

なのでこのようなソースを書いてみたのですが以下の点がわからず困っております。
・文字列をPictureBoxの中心に描画する方法。
・背景色を全体にかけるのではなく、文字列の大きさを測り、その後ろに背景色をつける方法。(背景色の透明度はOpacityと同じ。)

この場合はどうすればよいのでしょうか。

引用返信 編集キー/
■74591 / inTopicNo.4)  Re[3]: 半透明のラベル
□投稿者/ Azulean (404回)-(2015/01/11(Sun) 00:07:29)
2015/01/11(Sun) 00:08:18 編集(投稿者)

No74590 (ソースハンター さん) に返信
> ・文字列をPictureBoxの中心に描画する方法。

MeasureString で文字列の大きさを測り、ClientRectangle と組み合わせて中央位置から左上にずらした位置を求める。
以下は、このままではコンパイルは通りませんが、イメージとして示します。

Size sz = pe.Graphics.MeasureString(...);
Point point = new Point((ClientRectangle.Width - sz.Width) / 2, (ClientRectangle.Height - sz.Height) / 2);
// 全体の幅から文字列の幅を引いて、その結果を半分にすれば中央から文字列の幅の半分だけ左にずらした結果を得られる


> ・背景色を全体にかけるのではなく、文字列の大きさを測り、その後ろに背景色をつける方法。(背景色の透明度はOpacityと同じ。)

前述のように中央から左上にずらした起点と MeasureString で得たサイズからその矩形を描けば良いでしょう。
引用返信 編集キー/
■74592 / inTopicNo.5)  Re[4]: 半透明のラベル
□投稿者/ ソースハンター (3回)-(2015/01/11(Sun) 08:07:25)
    回答ありがとうございます。これでうまくいきそうです。
    せっかくなので完成したソースを載せていきたいと思います。

    public partial class CustomControl2 : PictureBox
    {
        [DefaultValue(1.0)]
        public double Opacity { get; set; }

        public Color CoverBackColor { get; set; }

        [DefaultValue("")]
        public string strTest { get; set; }

        public CustomControl2()
        {
            InitializeComponent();
            strTest = "0";

            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.SetStyle(ControlStyles.DoubleBuffer, true);
            this.SetStyle(ControlStyles.UserPaint, true);
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);

            this.BackColor = Color.Transparent;
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            base.OnPaint(pe);

            int alpha = Math.Min(Math.Max((int)Math.Round(255 * Opacity), 0), 255);
            System.Drawing.Font font = new System.Drawing.Font("MS UI Gothic", 20);

            SizeF sz = pe.Graphics.MeasureString(strTest, font);
            Point point = new Point((ClientRectangle.Width - (int)sz.Width) / 2, (ClientRectangle.Height - (int)sz.Height) / 2);

            using (var brush = new SolidBrush(Color.FromArgb(alpha, CoverBackColor)))
            {
                pe.Graphics.FillRectangle(brush, new Rectangle(point.X, point.Y, (int)sz.Width, (int)sz.Height));
            }

            using (var brush = new SolidBrush(Color.Blue))
            {
                pe.Graphics.DrawString(strTest, font, brush, point);
            }
        }
    }

解決済み
引用返信 編集キー/
■74593 / inTopicNo.6)  Re[5]: 半透明のラベル
□投稿者/ Azulean (405回)-(2015/01/11(Sun) 08:35:23)
2015/01/11(Sun) 08:38:44 編集(投稿者)

1点忘れていました。
Font は IDisposable なものですので、Dispose をきちんと呼ぶか、using(...) { } を使うかしましょう。


(おまけ)
今のやり方が悪いわけではありませんが、こういったパターンもあるということで。

SizeF szf = ...;
Size sz = Size.Round(szf); // Size型へ丸められる

Point pt;
Rectangle rect = new Rectangle(pt, sz); // Point と Size で作れる。
解決済み
引用返信 編集キー/
■74594 / inTopicNo.7)  Re[6]: 半透明のラベル
□投稿者/ ソースハンター (4回)-(2015/01/11(Sun) 09:41:11)
なるほど。ありがとうございます。
修正した部分だけ掲載します。
細かい話ですがこういう細かい手間で手抜くと後で大きく効いてくるんですよね…。

        protected override void OnPaint(PaintEventArgs pe)
        {
            base.OnPaint(pe);

            int alpha = Math.Min(Math.Max((int)Math.Round(255 * Opacity), 0), 255);
            
            using(System.Drawing.Font font = new System.Drawing.Font("MS UI Gothic", 20))
            {
                SizeF szf = pe.Graphics.MeasureString(strTest, font);
                Size sz = Size.Round(szf);
                Point point = new Point((ClientRectangle.Width - (int)sz.Width) / 2, (ClientRectangle.Height - (int)sz.Height) / 2);
                Rectangle rect = new Rectangle(point, sz);

                using (var brush = new SolidBrush(Color.FromArgb(alpha, CoverBackColor)))
                {
                    pe.Graphics.FillRectangle(brush, rect);
                }

                using (var brush = new SolidBrush(Color.White))
                {
                    pe.Graphics.DrawString(strTest, font, brush, point);
                }
            }
        }

解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -