1. 程式人生 > >C# 系統應用之透明罩MyOpaqueLayer實現360介面陰影效果

C# 系統應用之透明罩MyOpaqueLayer實現360介面陰影效果

在完成“個人電腦使用記錄清除軟體”中,我設計的winform介面需要應用到類似於"360安全衛士"的透明罩效果,文章主要引述瞭如何使用自定義元件MyOpaqueLayer,並自定義類OpaqueCommand中定義顯示透明罩函式ShowOpaqueLayer和隱藏透明罩函式HideOpaqueLayer實現,同時如何對控制元件新增透明罩及遇到的問題.

一.自定義透明罩MyOpaqueLayer元件

(宣告:此段程式碼引用自海華部落格http://www.cnblogs.com/JuneZhang/archive/2012/07/06/2579215.html)
在新增透明罩控制元件\元件時,我的想法是"右鍵專案->新增->新增控制元件",但新增沒有成功,在網上也沒有講到該新增的基礎方法,由於以前也沒遇到過自定義控制元件的問題,所以只好採取的方法是拖拽修改過MyOpaqueLayer.cs檔案至專案中,具體程式碼如下(含詳細註釋):

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

namespace MyOpaqueLayer
{
    /* 
     * [ToolboxBitmap(typeof(MyOpaqueLayer))]
     * 用於指定當把你做好的自定義控制元件新增到工具欄時,工具欄顯示的圖示。
     * 正確寫法應該是
     * [ToolboxBitmap(typeof(XXXXControl),"xxx.bmp")]
     * 其中XXXXControl是你的自定義控制元件,"xxx.bmp"是你要用的圖示名稱。
    */
    [ToolboxBitmap(typeof(MyOpaqueLayer))]

    /// <summary>
    /// 自定義控制元件:透明罩控制元件(繼承Control)
    /// </summary>
    public class MyOpaqueLayer : System.Windows.Forms.Control
    {
        private bool _transparentBG = true;       //是否使用透明
        private int _alpha = 125;                 //設定透明度
        
        private System.ComponentModel.Container components = new System.ComponentModel.Container();
        public MyOpaqueLayer()
            : this(125, true)
        {
        }

        public MyOpaqueLayer(int Alpha, bool IsShowLoadingImage)
        {
            SetStyle(System.Windows.Forms.ControlStyles.Opaque, true);  //設定控制元件樣式
            base.CreateControl();                                       //建立控制元件
            this._alpha = Alpha;
            //放置載入進度的圖片程式碼此處被省略
        }

        //釋放元件佔用記憶體
        protected override void Dispose(bool disposing)                 
        {
            if (disposing)
            {
                if (!((components == null)))
                {
                    components.Dispose();
                }
            }
            base.Dispose(disposing);
        }

        /// <summary>
        /// 自定義繪製窗體
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
        {
            float vlblControlWidth;
            float vlblControlHeight;

            Pen labelBorderPen;                     //定義Pen
            SolidBrush labelBackColorBrush;         //定義單色畫筆

            if (_transparentBG)                     //使用透明
            {
                Color drawColor = Color.FromArgb(this._alpha, this.BackColor);
                labelBorderPen = new Pen(drawColor, 0);
                labelBackColorBrush = new SolidBrush(drawColor);
            }
            else
            {
                labelBorderPen = new Pen(this.BackColor, 0);
                labelBackColorBrush = new SolidBrush(this.BackColor);
            }
            base.OnPaint(e);
            vlblControlWidth = this.Size.Width;
            vlblControlHeight = this.Size.Height;
            e.Graphics.DrawRectangle(labelBorderPen, 0, 0, vlblControlWidth, vlblControlHeight);
            e.Graphics.FillRectangle(labelBackColorBrush, 0, 0, vlblControlWidth, vlblControlHeight);
        }

        //獲取建立控制元件控制代碼時所需要的建立引數
        protected override CreateParams CreateParams //v1.10 
        {
            get
            {
                CreateParams cp = base.CreateParams;  //擴充套件派生類CreateParams屬性
                cp.ExStyle |= 0x00000020;             //開啟WS_EX_TRANSPARENT,使控制元件支援透明
                return cp;
            }
        }

        /*
         * [Category("myOpaqueLayer"), Description("是否使用透明,預設為True")]
         * 一般用於說明你自定義控制元件的屬性(Property)
         * Category用於說明該屬性屬於哪個分類,Description自然就是該屬性的含義解釋。
         */
        [Category("MyOpaqueLayer"), Description("是否使用透明,預設為True")]
        public bool TransparentBG
        {
            get
            {
                return _transparentBG;
            }
            set
            {
                _transparentBG = value;
                this.Invalidate();
            }
        }
        //設定透明度
        [Category("MyOpaqueLayer"), Description("設定透明度")]
        public int Alpha
        {
            get
            {
                return _alpha;
            }
            set
            {
                _alpha = value;
                this.Invalidate();
            }
        }

        //初始化窗體
        private void InitializeComponent()
        {
            this.SuspendLayout();      //臨時掛起控制元件的佈局邏輯,它與ResumeLayout()配合使用
            this.ResumeLayout(false);  //恢復正常邏輯
        }
    }
}

二.自定義透明罩類OpaqueCommand

在第一部分我們已經自定義透明罩元件,此時需要自定義類OpaqueCommand並呼叫其方法ShowOpaqueLayer(顯示遮罩層)和HideOpaqueLayer(隱藏遮罩層).可以在“解決方法”中右鍵專案名->新增->類,具體程式碼如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace EMSecure
{
    class OpaqueCommand
    {
        //透明罩
        private MyOpaqueLayer.MyOpaqueLayer m_OpaqueLayer = null;

        /// <summary>
        /// 顯示透明層
        /// </summary>
        /// <param name="control">控制元件</param>
        /// <param name="alpha">透明度</param>
        /// <param name="isShowLoadingImage">是否顯示圖示</param>
        public void ShowOpaqueLayer(Control control, int alpha, bool isShowLoadingImage)
        {
            try
            {
                if (this.m_OpaqueLayer == null)
                {
                    this.m_OpaqueLayer = new MyOpaqueLayer.MyOpaqueLayer(alpha, isShowLoadingImage);
                    control.Controls.Add(this.m_OpaqueLayer);
                    this.m_OpaqueLayer.Dock = DockStyle.Fill;
                    this.m_OpaqueLayer.BringToFront();
                }
                this.m_OpaqueLayer.Enabled = true;
                this.m_OpaqueLayer.Visible = true;
            }
            catch (Exception msg)              //異常處理
            {
                MessageBox.Show(msg.Message);
            }
        }

        /// <summary>
        /// 隱藏透明層
        /// </summary>
        public void HideOpaqueLayer()
        {
            try
            {
                if (this.m_OpaqueLayer != null)
                {
                    this.m_OpaqueLayer.Visible = false;
                    this.m_OpaqueLayer.Enabled = false;
                }
            }
            catch (Exception msg)             //異常處理
            {
                MessageBox.Show(msg.Message);
            }
        }
    }
}

三.使用透明罩

在定義透明罩控制元件和類後,如何實現該介面的效果,我推薦的方法是:
1.設定toolBar控制元件,在items(集合)中新增相應的圖示\文字構成不同的ToolItem,每次透明罩遮掩不同的Item即可,如果是wfp使用TabControl\TabItem.但由於toolBar被toolStrip替代,不太會使用該控制元件,但仍然推薦該方法(有的沒有定義透明罩控制元件,而是通過3張透明程度不同的圖,設定可見屬性實現該效果).執行結果:


2.在程式碼設計器Form中新增MyOpaqueLayer控制元件,此時就能看見6個透明罩的MyOpaqueLayer控制元件,該方法不需要設定自定義類OpaqueCommand呼叫其方法,而是設定如下程式碼:

//滑鼠離開
private void myOpaqueLayer1_MouseLeave(object sender, EventArgs e)
{
    this.myOpaqueLayer1.Visible = false;
    this.label4.ForeColor = Color.White;
}
//滑鼠進入
private void pictureBox1_MouseEnter(object sender, EventArgs e)
{
    this.myOpaqueLayer1.Visible = true;
    this.label4.ForeColor = Color.Yellow;
}

設計器中form如下圖所示:

但由於不知道如何新增該控制元件拖動至設計器中,所以我採取的方法是
3.自定義6個panel,通過滑鼠事件進入panelmol1_MouseEnter(object sender, EventArgs e)\滑鼠離開事件panelmol1_MouseLeave(object sender, EventArgs e)\滑鼠點選事件panelmol1_MouseClick(object sender, EventArgs e)實現,最後我的執行結果如下圖所示:


下面只給出使用透明罩控制元件和類的基本呼叫程式碼並省略Click部分(因為做的不是很好),請讀者體會與自己設計:

//自定義類OpaqueCommand
OpaqueCommand cmd = new OpaqueCommand();
//定義點選panel時透明罩情況
bool isClick = false;

//滑鼠進入"清除IE"
private void panel_mol1_MouseEnter(object sender, EventArgs e)
{
    //透明罩設定 沒點選才取消透明罩
    cmd.ShowOpaqueLayer(panel_mol1, 125, true);
}
private void panel_mol1_MouseEnter(object sender, EventArgs e)
{
    cmd.HideOpaqueLayer();
}