開始寫這一系列博客之前先要向大家說聲抱歉,放肆雷特建立很久卻很少有更新。當然博客人氣也不旺,大部分都是看的人多評論收藏的人少。一直想要改變這種狀態,正好趕上了最近工作上做了一個高仿360安全衛士窗體。所以將開發歷程分享出來,一來希望能和大家交流共同學習成長;二來希望自己的放肆雷特能有人光顧。
這一系列的文章所用到的技術首先要感謝蘇飛大哥,我也是在很早以前看了他的QQ皮膚制作文章之后得到的靈感和一些相關知識。在這里幫他的C#論壇打個廣告,里面有不少比較有用的資料。蘇飛大哥也是很用心的打理這個論壇,論壇地址http://www.sufeinet.com/。
說了這么多也該進入主題了,首先為了讓大家有興趣看下去而且認同我開發的這個皮膚,所以先傳上本程序的界面截圖(不喜勿噴)。同時本人也先聲明,本人屬屌絲一枚,想法和思路可能比較落后,如果你有比較不錯的想法和思路可以在本論壇中尋找本人qq或評論本文。
第一章:360安全衛士窗體素材提取
360安全衛士的窗體使用的素材比之前QQ的素材更容易提取首先安裝360安全衛士,如果怕自己電腦中毒的請使用虛擬機進行安裝。在這里不提供下載鏈接。安裝好之后打開安裝目錄,我這里以安裝到C盤為准:C:\Program Files (x86)\360\360safe\Config\newui\themes\default
打開后,將default_theme.ui文件拷貝出來。再將它的后綴改名為rar。之后的操作你懂的呀。。操作之后得到
第二章:360安全衛士風格按鈕開發
得到以上素材之后開始正式的編碼,第一個要開發的控件是Button控件,為什么呢?因為窗體上的關閉、最大化、最小化這些按鈕都可以使用。系統里面用到的WinApi類我就不放上來了,網上一搜一大把,如果有需要的可以單獨向我索取。寫按鈕前,先枚舉該按鈕的所有狀態,我這里定義5個狀態,應該比較全了:
1 /// <summary> 2 /// 枚舉按鈕狀態 3 /// </summary> 4 public enum State 5 { 6 Normal = 1,//按鈕默認時 7 MouseOver = 2,//鼠標移上按鈕時 8 MouseDown = 3,//鼠標按下按鈕時 9 Disable = 4,//當不啟用按鈕時(也就是按鈕屬性Enabled==Ture時) 10 Default = 5//控件得到Tab焦點時 11 }
重繪按鈕以及重繪其它控件及窗體用到的方法:
1、該方法是將素材切割后再進行繪制,這樣在按鈕大小發生改變時也不會對素材的大小有影響:
1 /// <summary> 2 /// 繪圖對像 3 /// </summary> 4 /// <param name="g">繪圖對像</param> 5 /// <param name="img">圖片</param> 6 /// <param name="r">繪置的圖片大小、坐標</param> 7 /// <param name="lr">繪置的圖片邊界</param> 8 /// <param name="index">當前狀態</param> 9 /// <param name="Totalindex">狀態總數</param> 10 public static void DrawRect(Graphics g, Bitmap img, Rectangle r, Rectangle lr, int index, int Totalindex) 11 { 12 if (img == null) return; 13 Rectangle r1, r2; 14 int x = (index - 1) * img.Width / Totalindex; 15 int y = 0; 16 int x1 = r.Left; 17 int y1 = r.Top; 18 19 if (r.Height > img.Height && r.Width <= img.Width / Totalindex) 20 { 21 r1 = new Rectangle(x, y, img.Width / Totalindex, lr.Top); 22 r2 = new Rectangle(x1, y1, r.Width, lr.Top); 23 g.DrawImage(img, r2, r1, GraphicsUnit.Pixel); 24 25 r1 = new Rectangle(x, y + lr.Top, img.Width / Totalindex, img.Height - lr.Top - lr.Bottom); 26 r2 = new Rectangle(x1, y1 + lr.Top, r.Width, r.Height - lr.Top - lr.Bottom); 27 if ((lr.Top + lr.Bottom) == 0) r1.Height = r1.Height - 1; 28 g.DrawImage(img, r2, r1, GraphicsUnit.Pixel); 29 30 r1 = new Rectangle(x, y + img.Height - lr.Bottom, img.Width / Totalindex, lr.Bottom); 31 r2 = new Rectangle(x1, y1 + r.Height - lr.Bottom, r.Width, lr.Bottom); 32 g.DrawImage(img, r2, r1, GraphicsUnit.Pixel); 33 } 34 else 35 if (r.Height <= img.Height && r.Width > img.Width / Totalindex) 36 { 37 r1 = new Rectangle(x, y, lr.Left, img.Height); 38 r2 = new Rectangle(x1, y1, lr.Left, r.Height); 39 g.DrawImage(img, r2, r1, GraphicsUnit.Pixel); 40 r1 = new Rectangle(x + lr.Left, y, img.Width / Totalindex - lr.Left - lr.Right, img.Height); 41 r2 = new Rectangle(x1 + lr.Left, y1, r.Width - lr.Left - lr.Right, r.Height); 42 g.DrawImage(img, r2, r1, GraphicsUnit.Pixel); 43 r1 = new Rectangle(x + img.Width / Totalindex - lr.Right, y, lr.Right, img.Height); 44 r2 = new Rectangle(x1 + r.Width - lr.Right, y1, lr.Right, r.Height); 45 g.DrawImage(img, r2, r1, GraphicsUnit.Pixel); 46 } 47 else 48 if (r.Height <= img.Height && r.Width <= img.Width / Totalindex) { r1 = new Rectangle((index - 1) * img.Width / Totalindex, 0, img.Width / Totalindex, img.Height); g.DrawImage(img, new Rectangle(x1, y1, r.Width, r.Height), r1, GraphicsUnit.Pixel); } else if (r.Height > img.Height && r.Width > img.Width / Totalindex) 49 { 50 //top-left 51 r1 = new Rectangle(x, y, lr.Left, lr.Top); 52 r2 = new Rectangle(x1, y1, lr.Left, lr.Top); 53 g.DrawImage(img, r2, r1, GraphicsUnit.Pixel); 54 55 //top-bottom 56 r1 = new Rectangle(x, y + img.Height - lr.Bottom, lr.Left, lr.Bottom); 57 r2 = new Rectangle(x1, y1 + r.Height - lr.Bottom, lr.Left, lr.Bottom); 58 g.DrawImage(img, r2, r1, GraphicsUnit.Pixel); 59 60 //left 61 r1 = new Rectangle(x, y + lr.Top, lr.Left, img.Height - lr.Top - lr.Bottom); 62 r2 = new Rectangle(x1, y1 + lr.Top, lr.Left, r.Height - lr.Top - lr.Bottom); 63 g.DrawImage(img, r2, r1, GraphicsUnit.Pixel); 64 65 //top 66 r1 = new Rectangle(x + lr.Left, y, 67 img.Width / Totalindex - lr.Left - lr.Right, lr.Top); 68 r2 = new Rectangle(x1 + lr.Left, y1, 69 r.Width - lr.Left - lr.Right, lr.Top); 70 g.DrawImage(img, r2, r1, GraphicsUnit.Pixel); 71 72 //right-top 73 r1 = new Rectangle(x + img.Width / Totalindex - lr.Right, y, lr.Right, lr.Top); 74 r2 = new Rectangle(x1 + r.Width - lr.Right, y1, lr.Right, lr.Top); 75 g.DrawImage(img, r2, r1, GraphicsUnit.Pixel); 76 77 //Right 78 r1 = new Rectangle(x + img.Width / Totalindex - lr.Right, y + lr.Top, 79 lr.Right, img.Height - lr.Top - lr.Bottom); 80 r2 = new Rectangle(x1 + r.Width - lr.Right, y1 + lr.Top, 81 lr.Right, r.Height - lr.Top - lr.Bottom); 82 g.DrawImage(img, r2, r1, GraphicsUnit.Pixel); 83 84 //right-bottom 85 r1 = new Rectangle(x + img.Width / Totalindex - lr.Right, y + img.Height - lr.Bottom, 86 lr.Right, lr.Bottom); 87 r2 = new Rectangle(x1 + r.Width - lr.Right, y1 + r.Height - lr.Bottom, 88 lr.Right, lr.Bottom); 89 g.DrawImage(img, r2, r1, GraphicsUnit.Pixel); 90 91 //bottom 92 r1 = new Rectangle(x + lr.Left, y + img.Height - lr.Bottom, 93 img.Width / Totalindex - lr.Left - lr.Right, lr.Bottom); 94 r2 = new Rectangle(x1 + lr.Left, y1 + r.Height - lr.Bottom, 95 r.Width - lr.Left - lr.Right, lr.Bottom); 96 g.DrawImage(img, r2, r1, GraphicsUnit.Pixel); 97 98 //Center 99 r1 = new Rectangle(x + lr.Left, y + lr.Top, 100 img.Width / Totalindex - lr.Left - lr.Right, img.Height - lr.Top - lr.Bottom); 101 r2 = new Rectangle(x1 + lr.Left, y1 + lr.Top, 102 r.Width - lr.Left - lr.Right, r.Height - lr.Top - lr.Bottom); 103 g.DrawImage(img, r2, r1, GraphicsUnit.Pixel); 104 } 105 } 106 107 /// <summary> 108 /// 繪圖對像 109 /// </summary> 110 /// <param name="g"> 繪圖對像</param> 111 /// <param name="obj">圖片對像</param> 112 /// <param name="r">繪置的圖片大小、坐標</param> 113 /// <param name="index">當前狀態</param> 114 /// <param name="Totalindex">狀態總數</param> 115 public static void DrawRect(Graphics g, Bitmap img, Rectangle r, int index, int Totalindex) 116 { 117 if (img == null) return; 118 int width = img.Width / Totalindex; 119 int height = img.Height; 120 Rectangle r1, r2; 121 int x = (index - 1) * width; 122 int y = 0; 123 r1 = new Rectangle(x, y, width, height); 124 r2 = new Rectangle(r.Left, r.Top, r.Width, r.Height); 125 g.DrawImage(img, r2, r1, GraphicsUnit.Pixel); 126 }
2、該方法是將編譯好的圖片讀取出來
1 /// <summary> 2 /// 得到要繪置的圖片對像 3 /// </summary> 4 /// <param name="str">圖像在程序集中的地址</param> 5 /// <returns></returns> 6 public static Bitmap GetResBitmap(string str) 7 { 8 Stream sm; 9 sm = FindStream(str); 10 if (sm == null) return null; 11 return new Bitmap(sm); 12 } 13 14 /// <summary> 15 /// 得到圖程序集中的圖片對像 16 /// </summary> 17 /// <param name="str">圖像在程序集中的地址</param> 18 /// <returns></returns> 19 private static Stream FindStream(string str) 20 { 21 Assembly assembly = Assembly.GetExecutingAssembly(); 22 string[] resNames = assembly.GetManifestResourceNames(); 23 foreach (string s in resNames) 24 { 25 if (s == str) 26 { 27 return assembly.GetManifestResourceStream(s); 28 } 29 } 30 return null; 31 }
Ok,基礎打好之后就可以開始正式的進行按鈕繪制,代碼比較長,里面包括定義變量,定義按鈕屬性,處理按鈕構造函數。這里我分享關鍵部分重寫OnPaint代碼:
1 /// <summary> 2 /// 重繪控件 3 /// </summary> 4 /// <param name="e"></param> 5 protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) 6 { 7 if (BackImg == null) 8 { 9 base.OnPaint(e); 10 return; 11 } 12 13 int i = (int)state; 14 if (this.Focused && state != State.MouseDown && _IsTabFocus == true) i = 5; 15 if (!this.Enabled) i = 4; 16 Rectangle rc = this.ClientRectangle; 17 Graphics g = e.Graphics; 18 19 base.InvokePaintBackground(this, new PaintEventArgs(e.Graphics, base.ClientRectangle)); 20 try 21 { 22 if (BackImg != null) 23 { 24 if (_BacklightLTRB != Rectangle.Empty) 25 { 26 27 ImageDrawRect.DrawRect(g, BackImg, rc, Rectangle.FromLTRB(_BacklightLTRB.X, _BacklightLTRB.Y, _BacklightLTRB.Width, _BacklightLTRB.Height), i, 5); 28 } 29 else 30 { 31 ImageDrawRect.DrawRect(g, BackImg, rc, Rectangle.FromLTRB(10, 10, 10, 10), i, 5); 32 } 33 34 } 35 } 36 catch 37 { } 38 39 Image img = null; 40 Size txts, imgs; 41 42 txts = Size.Empty; 43 imgs = Size.Empty; 44 45 if (this.Image != null) 46 { 47 img = this.Image; 48 } 49 else if (this.ImageList != null && this.ImageIndex != -1) 50 { 51 img = this.ImageList.Images[this.ImageIndex]; 52 } 53 54 if (img != null) 55 { 56 imgs.Width = img.Width; 57 imgs.Height = img.Height; 58 } 59 60 StringFormat format1; 61 using (format1 = new StringFormat()) 62 { 63 format1.HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.Show; 64 SizeF ef1 = g.MeasureString(this.Text, this.Font, new SizeF((float)rc.Width, (float)rc.Height), format1); 65 txts = Size.Ceiling(ef1); 66 } 67 68 rc.Inflate(-4, -4); 69 if (imgs.Width * imgs.Height != 0) 70 { 71 Rectangle imgr = rc; 72 imgr = ImageDrawRect.HAlignWithin(imgs, imgr, this.ImageAlign); 73 imgr = ImageDrawRect.VAlignWithin(imgs, imgr, this.ImageAlign); 74 if (!this.Enabled) 75 { 76 ControlPaint.DrawImageDisabled(g, img, imgr.Left, imgr.Top, this.BackColor); 77 } 78 else 79 { 80 g.DrawImage(img, imgr.Left, imgr.Top, img.Width, img.Height); 81 } 82 } 83 84 Rectangle txtr = rc; 85 txtr = ImageDrawRect.HAlignWithin(txts, txtr, this.TextAlign); 86 txtr = ImageDrawRect.VAlignWithin(txts, txtr, this.TextAlign); 87 88 format1 = new StringFormat(); 89 format1.HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.Show; 90 91 if (this.RightToLeft == RightToLeft.Yes) 92 { 93 format1.FormatFlags |= StringFormatFlags.DirectionRightToLeft; 94 } 95 brush = new SolidBrush(this.ForeColor); 96 g.DrawString(this.Text, this.Font, brush, (RectangleF)txtr, format1); 97 brush.Dispose(); 98 99 }
其中關鍵部分已經出來,按鈕也基本繪制完成。下一篇我將分享重繪主窗體,其中過程也沒有詳細講解,主要原因是文采不好。如果有不了解的可以留言給我,我會及時回復。該皮膚的源碼由於項目上正在使用暫時不進行公布,如果本文的反響和關注度都不錯,我再決定是否提供下載。最后謝謝大家的關注。請期待下一篇的重繪主窗體。
本文來自 放肆雷特 | 胖子的技術博客