1. 程式人生 > >Winform繪製控制元件解決閃爍問題

Winform繪製控制元件解決閃爍問題

一開始用複合控制元件(就是在UserControl上面拖進去一些Label、Button之類的), 然後在把這個使用者控制元件加入到滾動容器中去,

可沒想到滾動過程簡直不忍直視,即使開啟了雙快取

 

  後來一想還是重寫onpaint自己繪製介面算了,但是說起繪製介面又麻煩,這可是個苦力活

  不過效果還是有的,流暢的讓你感覺不到卡 

  

  程式碼如下

  

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

namespace WindowsFormsApp1
{

    public partial class UserControl1 : UserControl
    {
        #region 私有屬性
        Font fontDict = new Font("Microsoft YaHei", 13);
        Font fontYb = new Font("Microsoft YaHei", 10);
        Font fontDesc = new Font("新宋體", 9);
        /// <summary>
        /// 發音圖示
        /// </summary>
        Image soundIcon = null;
        /// <summary>
        /// 發音圖示_高亮
        /// </summary>
        Image soundIconHigh = null;
        /// <summary>
        /// 遺忘圖示
        /// </summary>
        Image forgetIcon = null;
        /// <summary>
        /// 階段圖示
        /// </summary>
        Image gradeIcon = null;

        /// <summary>
        /// 組隊按鈕
        /// </summary>
        UIRectangle flagButton = null;

        /// <summary>
        /// 刪除按鈕
        /// </summary>
        UIRectangle delButton = null;

        Rectangle rectSound1;
        Rectangle rectSound2;
        /// <summary>
        /// 是否滑鼠進入sound1
        /// </summary>
        bool isEnterSound1 = false;
        /// <summary>
        /// 是否滑鼠進入sound2
        /// </summary>
        bool isEnterSound2 = false;

        event SoundEvent mouseEnterSound;

        event EventHandler mouseClickSound;

        event EventHandler mouseClickFlag;

        event EventHandler mouseClickDelete;
        #endregion

        /// <summary>
        /// 單詞名稱
        /// </summary>
        public string DictName { set; get; }

        /// <summary>
        /// 英音標
        /// </summary>
        public string USKSpell { set; get; }

        /// <summary>
        /// 美音標
        /// </summary>
        public string USASpell { set; get; }

        /// <summary>
        /// 釋義
        /// </summary>
        public string Descript { set; get; }

        /// <summary>
        /// 遺忘次數
        /// </summary>
        public int ForgetCount { set; get; }

        /// <summary>
        /// 階段名稱
        /// </summary>
        public string GradeName { set; get; }

        /// <summary>
        /// 滑鼠進入發音圖示事件
        /// </summary>
        public event SoundEvent OnMouseEnterSound {
            add {
                mouseEnterSound += value;
            }
            remove {
                mouseEnterSound -= value;
            }
        }

        /// <summary>
        /// 滑鼠點擊發音圖示事件
        /// </summary>
        public event EventHandler OnClickSound {
            add {
                mouseClickSound += value;
            }
            remove {
                mouseClickSound -= value;
            }
        }

        /// <summary>
        /// 滑鼠點選旗幟事件
        /// </summary>
        public event EventHandler OnClickFlag {
            add {
                mouseClickFlag += value;
            }
            remove {
                mouseClickFlag -= value;
            }
        }
       
        /// <summary>
        /// 滑鼠點選刪除按鈕事件
        /// </summary>
        public event EventHandler OnClickDelete {
            add {
                mouseClickDelete += value;
            }
            remove {
                mouseClickDelete -= value;
            }
        }
        public UserControl1()
        {
            this.DoubleBuffered = true;
            InitializeComponent();
            this.Load += UserControl1_Load;

        }

        /// <summary>
        /// 載入完畢
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void UserControl1_Load(object sender, EventArgs e)
        {
            //載入圖片資源
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(UserControl1));
            soundIcon = ((System.Drawing.Image)(resources.GetObject("sound_play_gray")));
            soundIconHigh = ((System.Drawing.Image)(resources.GetObject("sound_play")));
            forgetIcon = ((System.Drawing.Image)(resources.GetObject("ico_question")));
            gradeIcon = ((System.Drawing.Image)(resources.GetObject("ico_grade")));
            flagButton = new UIRectangle(((System.Drawing.Image)(resources.GetObject("ico_flag_normal"))), ((System.Drawing.Image)(resources.GetObject("ico_flag_focus"))));
            delButton = new UIRectangle(((System.Drawing.Image)(resources.GetObject("ico_delete_normal"))), ((System.Drawing.Image)(resources.GetObject("ico_delete_focus"))));
            this.Margin = new Padding(0);

            DictName = "Caption";
            USKSpell = "英 [caption]";
            USASpell = "美 [caption]";
            Descript = "釋義:n. 說明文字 v.給(圖片、照片等)加說明文字釋義:n. 說明文字 v.給(圖片、照片等)加說明文字釋義:n. 說明文字 v.給(圖片、照片等)加說明文字";
            GradeName = "青銅 x3";
            ForgetCount = 9;
        }

        /// <summary>
        /// 控制元件重繪
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaint(PaintEventArgs e)
        {
            
            //單詞寬度
            float dictWidth = GetTextWidth(e.Graphics, DictName, fontDict);
            //USK音標寬度
            float uskWidth = GetTextWidth(e.Graphics, USKSpell, fontYb);
            //USA音標寬度
            float usaWidth = GetTextWidth(e.Graphics, USASpell, fontYb);
            //單詞階段寬度
            float gradeWidth = GetTextWidth(e.Graphics, GradeName, fontYb);
            float left = 10;
            //畫單詞
            e.Graphics.DrawString(DictName, fontDict, Brushes.Black, left, 5);
            left += dictWidth + 20;
            //畫音標
            e.Graphics.DrawString(USKSpell, fontYb, Brushes.Gray, left, 7);
            left += uskWidth + 5;
            #region 畫發音圖示1
            //發音圖示
            if (isEnterSound1)
            {
                e.Graphics.DrawImage(soundIconHigh, left, 9, 15, 15);
                rectSound1 = new Rectangle((int)left, 9, 15, 15);
                left += 30;
            }
            else
            {
                e.Graphics.DrawImage(soundIcon, left, 9, 15, 15);
                rectSound1 = new Rectangle((int)left, 9, 15, 15);
                left += 30;
            }
            #endregion
            //畫音標
            e.Graphics.DrawString(USASpell, fontYb, Brushes.Gray, left, 7);
            left += usaWidth + 5;
            #region 畫發音圖示2
            if (isEnterSound2)
            {
                //發音圖示
                e.Graphics.DrawImage(soundIconHigh, left, 9, 15, 15);
                rectSound2 = new Rectangle((int)left, 9, 15, 15);
                left += 50;
            }
            else {
                //發音圖示
                e.Graphics.DrawImage(soundIcon, left, 9, 15, 15);
                rectSound2 = new Rectangle((int)left, 9, 15, 15);
                left += 50;
            }
            #endregion

            #region try畫遺忘次數
            if (ForgetCount > 0)
            {
                e.Graphics.DrawImage(forgetIcon, new Rectangle((int)left,9,15,15));
                left += 15+3;
                e.Graphics.DrawString(ForgetCount.ToString(), fontYb, Brushes.Gray, left, 7);
                left += 30;
            }
            #endregion

            #region 畫單詞階段(熟悉度)
            e.Graphics.DrawImage(gradeIcon, new Rectangle((int)left, 9, 15, 15));
            left += 15 + 3;
            e.Graphics.DrawString(GradeName, fontYb, Brushes.Gray, left, 7);
            left += gradeWidth + 5;
            #endregion

            #region 畫組隊旗幟
            if (flagButton.IsEnter)
            {
                flagButton.Rect = new Rectangle((int)left, 7, 18, 18);
                e.Graphics.DrawImage(flagButton.HightImage, flagButton.Rect);
                left += 15 + 5;
            }
            else {
                flagButton.Rect = new Rectangle((int)left, 7, 18, 18);
                e.Graphics.DrawImage(flagButton.NormalImage, flagButton.Rect);
                left += 15 + 5;
            }
            #endregion

            #region 畫刪除圖示
            if (delButton.IsEnter)
            {
                delButton.Rect = new Rectangle(this.Width-25, 7, 18, 18);
                e.Graphics.DrawImage(delButton.HightImage, delButton.Rect);
            }
            else
            {
                delButton.Rect = new Rectangle(this.Width - 25, 7, 18, 18);
                e.Graphics.DrawImage(delButton.NormalImage, delButton.Rect);
            }

            #endregion
            //畫釋義
            e.Graphics.DrawString(Descript, fontDesc, Brushes.Gray, 12, 40);
            //畫分割線
           // e.Graphics.DrawRectangle(Pens.Gray, new Rectangle(0,this.Height-1,this.Width,1));
            e.Graphics.DrawLine(Pens.WhiteSmoke,0,this.Height-1,this.Width,this.Height-1);
        }

        /// <summary>
        /// 滑鼠移動事件
        /// 判斷滑鼠是否進入某個矩形內
        /// 判斷滑鼠是否移出某個矩形內
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (IsInRangle(e.X, e.Y, rectSound1))
            {
                //滑鼠進入聲音1
                if (!isEnterSound1)
                {
                    isEnterSound1 = true;
                    this.Invalidate(rectSound1);
                    if (mouseEnterSound != null) {
                        //響應事件
                        
                        mouseEnterSound(this,0);
                    }
                }
            }
            else if (IsInRangle(e.X, e.Y, rectSound2))
            {
                if (!isEnterSound2)
                {
                    //滑鼠進入聲音2
                    isEnterSound2 = true;
                    this.Invalidate(rectSound2);
                    if (mouseEnterSound != null){
                        //響應事件
                        mouseEnterSound(this, 1);
                    }
                }
            }
            else if (IsInRangle(e.X, e.Y, flagButton.Rect))
            {
                //滑鼠進入旗幟按鈕
                if (!flagButton.IsEnter)
                {
                    flagButton.IsEnter = true;
                    this.Invalidate(flagButton.Rect);
                }
            }
            else if (IsInRangle(e.X, e.Y, delButton.Rect)) {
                //滑鼠進入刪除按鈕
                if (!delButton.IsEnter) {
                    delButton.IsEnter = true;
                    this.Invalidate(delButton.Rect);
                }
            }
            else
            {
                if (isEnterSound1)
                {
                    isEnterSound1 = false;
                    this.Invalidate(rectSound1);
                }
                if (isEnterSound2)
                {
                    isEnterSound2 = false;
                    this.Invalidate(rectSound2);
                }
                if (flagButton.IsEnter)
                {
                    flagButton.IsEnter = false;
                    this.Invalidate(flagButton.Rect);
                }
                if (delButton.IsEnter) {
                    delButton.IsEnter = false;
                    this.Invalidate(delButton.Rect);
                }
            }
        }

        /// <summary>
        /// 滑鼠點選事件
        /// 響應各個元素的點選事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseClick(MouseEventArgs e)
        {
            base.OnMouseClick(e);
            if (IsInRangle(e.X, e.Y, rectSound1))
            {
                if (mouseEnterSound != null)
                {
                    mouseEnterSound(this, 0);
                }
            }
            else if (IsInRangle(e.X, e.Y, rectSound2))
            {
                if (mouseEnterSound != null)
                {
                    mouseEnterSound(this, 1);
                }
            }
            else if (IsInRangle(e.X, e.Y, flagButton.Rect))
            {
                if (mouseClickFlag != null)
                {
                    mouseClickFlag(this, e);
                }
            }
            else if (IsInRangle(e.X, e.Y, delButton.Rect)) {
                if (mouseClickDelete != null) {
                    mouseClickDelete(this,e);
                }
            }
        }
        /// <summary>
        /// 判斷是否再此矩形內
        /// </summary>
        /// <param name="rect"></param>
        /// <returns></returns>
        bool IsInRangle(int x,int y,Rectangle rect) {
            if (x >= rect.Left && x <= rect.Left + rect.Width
                 && y >= rect.Top && y <= rect.Top + rect.Height)
            {
                return true;
            }
            return false;
        }
        /// <summary>
        /// 取文字寬度
        /// </summary>
        /// <param name="gp"></param>
        /// <param name="str"></param>
        /// <param name="font"></param>
        /// <returns></returns>
        float GetTextWidth(Graphics gp,string str, Font font) {
            SizeF size = gp.MeasureString(DictName, fontDict);
            return size.Width;
        }

       
    }

    /// <summary>
    /// 描述ui元素
    /// </summary>
    class UIRectangle {
        public Image NormalImage { set; get; }
        public Image HightImage { set; get;}
        public Rectangle Rect { set; get; }
        public bool IsEnter { set; get; }

        public UIRectangle(Image img1,Image img2) {
            this.NormalImage = img1;
            this.HightImage = img2;
            IsEnter = false;
        }
    }

    /// <summary>
    /// 發音圖示觸發事件型別
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="index"></param>
    public delegate void SoundEvent(object sender, int index);
}