Winform繪製控制元件解決閃爍問題
阿新 • • 發佈:2018-12-30
一開始用複合控制元件(就是在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); }