none
Layering Opaque Panels & BringToFront() [code included] - Any Help Please? RRS feed

  • Question

  • I know the title isn't very descriptive, but that is because I'm not exactly sure what to ask here.

    In my application when the user clicks a button I want to bring up an opaque panel that covers all of the controls and then prompt the user for input. I've successfully created the opaque panel, however when I use BringToFront() it does in fact bring it to the front, but some elements appear not to be covered. See the link for a screenshot.



    In my example it appears that the Labels of my custom UserControl don't get their backgrounds colored. Am I forgetting something or is this happening by design of the UserControl?

    Code Snippet

    // TransPanel.cs

    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    using System.Data;
     
     
    namespace WindowsApplication1
    {
      /// <summary>
      /// Summary description for TransPanel.
      /// </summary>
      public class TransPanel : UserControl
      {
     
        public TransPanel ()
        {
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.EnableNotifyMessage, true);
        }
     
        protected override CreateParams CreateParams
        {
          get
          {
            CreateParams cp=base.CreateParams;
            cp.ExStyle|=0x00000020; //WS_EX_TRANSPARENT
            return cp;
          }
        }
     
        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
          //do not allow the background to be painted
        }
     
        protected override void OnPaint(PaintEventArgs e)
        {
          Rectangle rect = new Rectangle(0, 0, this.Width, this.Height);
          SolidBrush b = new SolidBrush(Color.FromArgb(205, Color.Black));
          e.Graphics.FillRectangle(b, rect);

          b.Dispose();
        }
      }
    }


    Code Snippet

    // UserControl1.cs

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Drawing;
    using System.Data;
    using System.Text;
    using System.Windows.Forms;

    namespace WindowsApplication1
    {
        public partial class UserControl1 : UserControl
        {
            private System.ComponentModel.IContainer components = null;
            protected override void Dispose(bool disposing)
            {
                if (disposing && (components != null))
                {
                    components.Dispose();
                }
                base.Dispose(disposing);
            }

            #region Component Designer generated code

            private void InitializeComponent()
            {
                this.label1 = new System.Windows.Forms.Label();
                this.SuspendLayout();
                //
                // label1
                //
                this.label1.AutoSize = true;
                this.label1.BackColor = System.Drawing.Color.Transparent;
                this.label1.Location = new System.Drawing.Point(25, 34);
                this.label1.Name = "label1";
                this.label1.Size = new System.Drawing.Size(35, 13);
                this.label1.TabIndex = 0;
                this.label1.Text = "label1";
                //
                // UserControl1
                //
                this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
                this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
                this.BackColor = System.Drawing.SystemColors.Highlight;
                this.Controls.Add(this.label1);
                this.Name = "UserControl1";
                this.ResumeLayout(false);
                this.PerformLayout();

            }

            #endregion

            private System.Windows.Forms.Label label1;


            public UserControl1()
            {
                InitializeComponent();
                label1.SendToBack();
            }
        }
    }


    Code Snippet

    // Form1.cs

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;

    namespace WindowsApplication1
    {
        public partial class Form1 : Form
        {
            /// <summary>
            /// Required designer variable.
            /// </summary>
            private System.ComponentModel.IContainer components = null;

            /// <summary>
            /// Clean up any resources being used.
            /// </summary>
            /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
            protected override void Dispose(bool disposing)
            {
                if (disposing && (components != null))
                {
                    components.Dispose();
                }
                base.Dispose(disposing);
            }

            #region Windows Form Designer generated code

            /// <summary>
            /// Required method for Designer support - do not modify
            /// the contents of this method with the code editor.
            /// </summary>
            private void InitializeComponent()
            {
                this.label1 = new System.Windows.Forms.Label();
                this.label2 = new System.Windows.Forms.Label();
                this.userControl11 = new WindowsApplication1.UserControl1();
                this.SuspendLayout();
                //
                // label1
                //
                this.label1.AutoSize = true;
                this.label1.BackColor = System.Drawing.Color.Transparent;
                this.label1.Location = new System.Drawing.Point(13, 13);
                this.label1.Name = "label1";
                this.label1.Size = new System.Drawing.Size(35, 13);
                this.label1.TabIndex = 0;
                this.label1.Text = "label1";
                //
                // label2
                //
                this.label2.AutoSize = true;
                this.label2.BackColor = System.Drawing.Color.Transparent;
                this.label2.Location = new System.Drawing.Point(13, 43);
                this.label2.Name = "label2";
                this.label2.Size = new System.Drawing.Size(35, 13);
                this.label2.TabIndex = 1;
                this.label2.Text = "label2";
                //
                // userControl11
                //
                this.userControl11.Location = new System.Drawing.Point(304, 158);
                this.userControl11.Name = "userControl11";
                this.userControl11.Size = new System.Drawing.Size(150, 150);
                this.userControl11.TabIndex = 3;
                //
                // Form1
                //
                this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
                this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
                this.ClientSize = new System.Drawing.Size(629, 482);
                this.Controls.Add(this.userControl11);
                this.Controls.Add(this.label2);
                this.Controls.Add(this.label1);
                this.Name = "Form1";
                this.Text = "Form1";
                this.ResumeLayout(false);
                this.PerformLayout();

            }

            #endregion

            private System.Windows.Forms.Label label1;
            private System.Windows.Forms.Label label2;
            private UserControl1 userControl11;


            public Form1()
            {
                InitializeComponent();
                TransPanel tp = new TransPanel();
                this.Controls.Add(tp);
                tp.Location = new Point(2, 2);
                tp.Size = new Size(this.Width, this.Height);
                tp.BringToFront();
                userControl11.Invalidate();
            }
        }
    }


    Any help on figuring out how to gray out the label in the blue box would be awesome. Thank you!
    Thursday, September 6, 2007 6:03 PM

Answers

  • Hmm, looks familiar.  Transparency in Windows is a parlor trick and falls flat on its face in this case.  The label control clearly is painted last, after TransPanel, thus destroying the transparency effect.  I'd assume this has something to do with the fact that it is located on a UserControl and Windows fails to detect the proper Z-order.

    Another way to do this is to overlay the client area of your form with another form whose Opacity value is set to a value less than one.  Transparency in this case is done by the video adapter hardware and is both very fast and accurate.  Add a new form to your project, named FMask and paste this code:

    using System;
    using System.Drawing;
    using System.Windows.Forms;

    namespace WindowsApplication1 {
      public partial class FMask : Form {
        public FMask(Form parent) {
          InitializeComponent();
          this.FormBorderStyle = FormBorderStyle.None;
          this.BackColor = Color.Black;
          this.Opacity = 0.50;
          this.ShowInTaskbar = false;
          this.StartPosition = FormStartPosition.Manual;
          this.Size = parent.ClientSize;
          this.Location = parent.PointToScreen(Point.Empty);
          parent.Move += AdjustPosition;
          parent.SizeChanged += AdjustPosition;
        }
        private void AdjustPosition(object sender, EventArgs e) {
          Form parent = sender as Form;
          this.Location = parent.PointToScreen(Point.Empty);
          this.ClientSize = parent.ClientSize;
        }
      }
    }

    Then in your original Form1, remove the TransPanel code and add a Load event:
        private FMask overlay;
        private void Form1_Load(object sender, EventArgs e) {
          overlay = new FMask(this);
          overlay.Show(this);
        }

    To remove the overlay, just call overlay.Close() and set overlay = null.
    Friday, September 7, 2007 7:15 PM
    Moderator

All replies

  • Hmm, looks familiar.  Transparency in Windows is a parlor trick and falls flat on its face in this case.  The label control clearly is painted last, after TransPanel, thus destroying the transparency effect.  I'd assume this has something to do with the fact that it is located on a UserControl and Windows fails to detect the proper Z-order.

    Another way to do this is to overlay the client area of your form with another form whose Opacity value is set to a value less than one.  Transparency in this case is done by the video adapter hardware and is both very fast and accurate.  Add a new form to your project, named FMask and paste this code:

    using System;
    using System.Drawing;
    using System.Windows.Forms;

    namespace WindowsApplication1 {
      public partial class FMask : Form {
        public FMask(Form parent) {
          InitializeComponent();
          this.FormBorderStyle = FormBorderStyle.None;
          this.BackColor = Color.Black;
          this.Opacity = 0.50;
          this.ShowInTaskbar = false;
          this.StartPosition = FormStartPosition.Manual;
          this.Size = parent.ClientSize;
          this.Location = parent.PointToScreen(Point.Empty);
          parent.Move += AdjustPosition;
          parent.SizeChanged += AdjustPosition;
        }
        private void AdjustPosition(object sender, EventArgs e) {
          Form parent = sender as Form;
          this.Location = parent.PointToScreen(Point.Empty);
          this.ClientSize = parent.ClientSize;
        }
      }
    }

    Then in your original Form1, remove the TransPanel code and add a Load event:
        private FMask overlay;
        private void Form1_Load(object sender, EventArgs e) {
          overlay = new FMask(this);
          overlay.Show(this);
        }

    To remove the overlay, just call overlay.Close() and set overlay = null.
    Friday, September 7, 2007 7:15 PM
    Moderator
  • Thanks for the reply. I've tried your suggestion in the past but was hoping I could do it by drawing my own panels Wink I've had some screwey instances where the overlay got stuck behind the parent. But I suppose I'll just have to be more careful about that. Thanks for your suggestion.
    Monday, September 10, 2007 11:18 AM
  • It will always stay on top, as long as you use the Show(owner) overload to show it.
    Monday, September 10, 2007 11:45 AM
    Moderator
  • Excellent solution! I was about to write something like this but figured I would look for it just in case someone had already done it. Why re-invent the wheel, right? Here we are! Thanks!
    Friday, September 28, 2018 2:34 PM