序 一直都是在看別人的博客,查到想要的,看完後把頁面一關就萬事大吉了,沒啥感覺;直到後來遇到了同樣的問題,總想不起來咋弄,關鍵是還查不到以前看過的,鬱悶!現在想想,還是“好記性不如爛筆頭”啊,自己弄過的東西總要留下的什麼呀,不然你都不知道自己曾經多麼優秀。註冊博客園也好久了,因為不知道該寫點啥,再加 ...
序
一直都是在看別人的博客,查到想要的,看完後把頁面一關就萬事大吉了,沒啥感覺;直到後來遇到了同樣的問題,總想不起來咋弄,關鍵是還查不到以前看過的,鬱悶!現在想想,還是“好記性不如爛筆頭”啊,自己弄過的東西總要留下的什麼呀,不然你都不知道自己曾經多麼優秀。註冊博客園也好久了,因為不知道該寫點啥,再加上懶,一直沒有去管它,今日有空,正好開張!
1. 需求說明
這個沒啥好說的,主要乾三個事,用電腦的照片查看器打開一張你寶貝的自拍照。
(1)拉動顯示視窗,圖片按照原有比例被放大和縮小,照片查看器中當圖片沒能完全顯示時,拉框時只是拉框,我們不管這個,只要圖片顯示視窗變了,那就按照原有比例被放大和縮小。
(2)滑鼠放在圖片的有效區域,滑鼠滾輪放大和縮小圖片,縮小時最小隻能到圖片原大小;放大無限制,照片查看器放大也有限制,咱也不管它。
(3)滑鼠放在圖片的有效區域,按住滑鼠左鍵平移圖片,平移時只能平移圖片有效範圍。
2. 功能分析
想想上面要實現的功能,結合C#,我們用Winform的窗體程式來實現,圖片顯示用PictureBox控制項,它有一個PictureBoxSizeMode屬性,值改成Zoom,這樣就能保證PictureBox控制項裡面的圖片隨PictureBox控制項大小改變而按照原有比例縮放,然後把PictureBox控制項放大Form窗體中,dock屬性改成Fill填滿就可以了,但dock屬性改成Fill填滿之後,PictureBox控制項的大小變得無法改變(我也是試了之後才知道的),一種有效的解決方案是在窗體裡面放一個Panel控制項,dock屬性Fill,然後把PictureBox控制項放在Panel中,大小改成和Panel控制項一樣大,再加一個Panel控制項的SizeChanged事件,隨時設置PictureBox控制項和Panel控制項一樣大。這裡不細說,具體看下麵的C#編碼實現,咱重點說說PictureBox控制項里的圖斑如何縮放和平移。
要想實現縮放和平移,首先我們得瞭解它實現的原理,這是下麵編碼實現的基礎。因為圖片隨PictureBox控制項大小改變而按照原有比例縮放,因此我們改變PictureBox控制項的大小,也就是它的Width和Height屬性,在視覺上就能看到圖片被放大和縮小,也就是縮放;當圖片被放大後,窗體中不能顯示完整的圖片內容,這時就需要我們通過平移來查看未能顯示在窗體上的圖片部分了,同樣的,我們只要改變PictureBox控制項的位置,也就是它的Left和Top屬性,就能把需要展示的圖片局部正好顯示在窗體上,從而在視覺上看到圖片平移。
原理簡單說明瞭一下後,所以,我們想要實現縮放與偏移,本質上就是計算PictureBox控制項的大小和位置,只要搞定了這個,縮放平移也就搞定了。那麼這個大小和位置咋算呢,請接著往下看。我們知道照片查看器縮放用的滑鼠滾輪,前滾放大,後滾縮小。PictureBox控制項中找一下,MouseWheel事件正好乾這個事。再一查,哎呀,SystemInformation.MouseWheelScrollLines代碼滾一格(微軟叫它制動器)代表多少行。那就好辦了,我們把這個多少行按一定的比例轉換成PictureBox控制項Left、Top、Width、Height四個屬性的增量,加上原值後,調整與顯示窗體大小以及圖片有效區域的位置關係,重新賦值回去就OK了。平移稍稍麻煩一點,其實也不是太麻煩。涉及到MouseDown、MouseMove、MouseUp三個事件,在滑鼠按下時記錄下按下點坐標,同時標識正在平移操作;在滑鼠移動時計算移動的距離,換算Left、Top的增量,並與顯示窗體大小和圖片有效區域做調整,最後賦值會這倆屬性;滑鼠彈起時結束平移操作標識。
3. 編碼實現
新建一個窗體應用程式,改窗體名稱為frmMian,在其內添加一個Panel控制項,命名pel;再在Panel控制項中添加一個PictureBox控制項,命名pboImage,以下為窗體類需要編寫的代碼:
public partial class frmMian : Form { public frmMian() { InitializeComponent(); this.pel.Dock = System.Windows.Forms.DockStyle.Fill; this.pel.SizeChanged += new System.EventHandler(this.pel_SizeChanged); this.pboImage.Margin = new System.Windows.Forms.Padding(0); this.pboImage.Location = new System.Drawing.Point(0, 0); this.pboImage.Size = new System.Drawing.Size(this.pel.Width, this.pel.Height); this.pboImage.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; this.pboImage.Cursor = Cursors.SizeAll; this.pboImage.MouseDown += new System.Windows.Forms.MouseEventHandler(this.pboImage_MouseDown); this.pboImage.MouseEnter += new System.EventHandler(this.pboImage_MouseEnter); this.pboImage.MouseMove += new System.Windows.Forms.MouseEventHandler(this.pboImage_MouseMove); this.pboImage.MouseUp += new System.Windows.Forms.MouseEventHandler(this.pboImage_MouseUp); this.pboImage.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.pboImage_MouseWheel); pboImage.Image = Image.FromFile(@"C:\寶貝自拍照.jpg"); } private System.Drawing.Point MouseDownPoint = new System.Drawing.Point();//平移時滑鼠按下的位置 private bool IsSelected = false; //滑鼠是否是按下狀態 //pboImage獲取焦點事件 private void pboImage_MouseEnter(object sender, EventArgs e) { pboImage.Focus(); } //pboImage滑鼠滾輪事件 private void pboImage_MouseWheel(object sender, MouseEventArgs e) { if (pboImage.Image == null) return; //計算縮放後的錨點和寬高 int i = e.Delta * SystemInformation.MouseWheelScrollLines / 4; int left = pboImage.Left - i / 2, top = pboImage.Top - i / 2; int width = pboImage.Width + i, heigth = pboImage.Height + i; if (i < 0) //縮小時需要考慮與顯示範圍間關係,放大時無需考慮 { //計算縮放後圖片有效範圍 double WidthScale = Convert.ToDouble(pboImage.Image.Width) / width; double HeigthScale = Convert.ToDouble(pboImage.Image.Height) / heigth; if (WidthScale > HeigthScale) { top = top + Convert.ToInt32(Math.Ceiling(heigth - (pboImage.Image.Height / WidthScale))) / 2; heigth = Convert.ToInt32(Math.Ceiling(pboImage.Image.Height / WidthScale)); } else { left = left + Convert.ToInt32(Math.Ceiling(width - (pboImage.Image.Width / HeigthScale))) / 2; width = Convert.ToInt32(Math.Ceiling(pboImage.Image.Width / HeigthScale)); } if (left > 0) //左側在顯示範圍內部,調整到左邊界 { if (width - left < pel.Width) width = pel.Width; else width = width - left; left = 0; } if (left + width < pel.Width)//右側在顯示範圍內部,調整到右邊界 { if (pel.Width - width > 0) left = 0; else left = pel.Width - width; width = pel.Width - left; } if (top > 0)//上側在顯示範圍內部,調整到上邊界 { if (heigth - top < pel.Height) heigth = pel.Height; else heigth = heigth - top; top = 0; } if (top + heigth < pel.Height)//下側在顯示範圍內部,調整到下邊界 { if (pel.Height - heigth > 0) top = 0; else top = pel.Height - heigth; heigth = pel.Height - top; } } pboImage.Width = width; pboImage.Height = heigth; pboImage.Left = left; pboImage.Top = top; } //pboImage滑鼠按下事件 private void pboImage_MouseDown(object sender, MouseEventArgs e) { if (pboImage.Image == null) return; if (e.Button == MouseButtons.Left) { //記錄摁下點坐標,作為平移原點 MouseDownPoint.X = PointToClient(System.Windows.Forms.Cursor.Position).X; MouseDownPoint.Y = PointToClient(System.Windows.Forms.Cursor.Position).Y; IsSelected = true; pboImage.Cursor = Cursors.Hand; } } //pboImage滑鼠移動事件 private void pboImage_MouseMove(object sender, MouseEventArgs e) { if (pboImage.Image == null) return; //計算圖片有效範圍 double WidthScale = Convert.ToDouble(pboImage.Image.Width) / pboImage.Width; double HeigthScale = Convert.ToDouble(pboImage.Image.Height) / pboImage.Height; int InvalidTop = pboImage.Top, InvalidHeigth = pboImage.Height, InvalidLeft = pboImage.Left, InvalidWidth = pboImage.Width; if (WidthScale > HeigthScale) { InvalidTop = InvalidTop + ((int)Math.Ceiling(InvalidHeigth - (pboImage.Image.Height / WidthScale))) / 2; InvalidHeigth = (int)Math.Ceiling(pboImage.Image.Height / WidthScale); } else { InvalidLeft = InvalidLeft + ((int)Math.Ceiling(InvalidWidth - (pboImage.Image.Width / HeigthScale))) / 2; InvalidWidth = (int)Math.Ceiling(pboImage.Image.Width / HeigthScale); } //滑鼠是否摁在圖片上 bool IsMouseInPanel = InvalidLeft < PointToClient(System.Windows.Forms.Cursor.Position).X && PointToClient(System.Windows.Forms.Cursor.Position).X < InvalidLeft + InvalidWidth && InvalidTop < PointToClient(System.Windows.Forms.Cursor.Position).Y && PointToClient(System.Windows.Forms.Cursor.Position).Y < InvalidTop + InvalidHeigth; if (IsSelected && IsMouseInPanel) { //計算平移後圖片有效範圍的錨點和寬高 int left = InvalidLeft + (PointToClient(System.Windows.Forms.Cursor.Position).X - MouseDownPoint.X); int top = InvalidTop + (PointToClient(System.Windows.Forms.Cursor.Position).Y - MouseDownPoint.Y); int right = left + InvalidWidth; int down = top + InvalidHeigth; if (left >= InvalidLeft && left >= 0) left = 0; //向右平移且平移後在顯示範圍內部,調整到左邊界 if (left < InvalidLeft && right <= pel.Width) left = left + pel.Width - right;//向左平移且平移後在顯示範圍內部,調整到右邊界 if (top >= InvalidTop && top >= 0) top = 0;//向下平移且平移後在顯示範圍內部,調整到上邊界 if (top < InvalidTop && down <= pel.Height) top = top + pel.Height - down;//向上平移且平移後在顯示範圍內部,調整到下 邊界 //有效範圍錨點換算到整體的錨點 left = left + pboImage.Left - InvalidLeft; top = top + pboImage.Top - InvalidTop; if (InvalidLeft <= 0) pboImage.Left = left; if (InvalidTop <= 0) pboImage.Top = top; //記錄當前平移點坐標,作為平移下一次代碼執行時的平移原點 MouseDownPoint.X = PointToClient(System.Windows.Forms.Cursor.Position).X; MouseDownPoint.Y = PointToClient(System.Windows.Forms.Cursor.Position).Y; } } //pboImage滑鼠彈起事件 private void pboImage_MouseUp(object sender, MouseEventArgs e) { if (pboImage.Image == null) return; IsSelected = false; pboImage.Cursor = Cursors.SizeAll; } //pel大小改變事件 private void pel_SizeChanged(object sender, EventArgs e) { pboImage.Left = 0; pboImage.Top = 0; pboImage.Width = pel.Width; pboImage.Height = pel.Height; } }參考代碼
作者:喵...魚...喵 出處:https://www.cnblogs.com/bwuwj/ 本文為作者原創,版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,否則保留追究法律責任的權利。 |