• 通过设置光标形状实现拖拽控件时跟随一张透明图片的效果


    以前做过一些winform的项目,实现标题描述的效果通常是在鼠标拖拽控件的时候,通常是在拖动过程中生成一个透明的form,把控件放进去,form的位置跟随鼠标一起改变。前几天和几位同事讨论winform的一些技巧和方法,正好又谈到这个,有同事提供了一种比较新颖的思路:就是生成一张透明的图片,设置成光标的形状。正好周末有时间试了一下。

      1     using System.Collections.Generic;
      2     using System.Drawing;
      3     using System.Windows.Forms;
      4 
      5     delegate void DropCallBack<in Source, in Target>(Source source, Target target)
      6         where Source : Control
      7         where Target : Control;
      8 
      9     interface IDragDropController<in Source, in Target>
     10         where Source : Control
     11         where Target : Control
     12     {
     13         void EnableDragDrop();
     14         void DisableDragDrop();
     15     }
     16 
     17     sealed class DragDropController<Source, Target> : IDragDropController<Source, Target>
     18         where Source : Control
     19         where Target : Control
     20     {
     21         private IEnumerable<Source> sources;
     22         private IEnumerable<Target> targets;
     23         private bool isMovePrepared;
     24         private Bitmap cursorImage;
     25         private Cursor cursor;
     26         private Cursor defaultCursor;
     27         private DropCallBack<Source, Target> dropCallBack;
     28 
     29         public DragDropController(IEnumerable<Source> sources, IEnumerable<Target> targets, DropCallBack<Source, Target> dropCallBack)
     30         {
     31             this.sources = sources;
     32             this.targets = targets;
     33             this.dropCallBack = dropCallBack;
     34         }
     35 
     36         public void EnableDragDrop()
     37         {
     38             this.DisableDragDrop();
     39             foreach (var source in this.sources)
     40             {
     41                 source.MouseDown += this.OnSourceMouseDown;
     42                 source.MouseMove += this.OnSourceMouseMove;
     43                 source.MouseUp += this.OnSourceMouseUp;                
     44             }
     45         }
     46 
     47         public void DisableDragDrop()
     48         {
     49             foreach (var source in this.sources)
     50             {
     51                 source.MouseDown -= this.OnSourceMouseDown;
     52                 source.MouseMove -= this.OnSourceMouseMove;
     53                 source.MouseUp -= this.OnSourceMouseUp;
     54             }
     55         }
     56 
     57         private void OnSourceMouseDown(object sender, MouseEventArgs e)
     58         {
     59             if (e.Button == MouseButtons.Left)
     60             {
     61                 var source = sender as Source;
     62                 if (source != null)
     63                 {
     64                     source.Capture = true;
     65                     this.isMovePrepared = true;
     66                 }
     67             }
     68         }
     69 
     70         private void OnSourceMouseMove(object sender, MouseEventArgs e)
     71         {
     72             if (this.isMovePrepared)
     73             {
     74                 var source = sender as Source;
     75                 if (source == null)
     76                 {
     77                     return;
     78                 }
     79 
     80                 if (this.cursor == null)
     81                 {
     82                     this.defaultCursor = source.Cursor;
     83                     // Generate an image for cursor
     84                     int cursorWidth = source.Width >= 2 * e.X ? 2 * (source.Width - e.X) : 2 * e.X;
     85                     int cursorHeight = source.Height >= 2 * e.Y ? 2 * (source.Height - e.Y) : 2 * e.Y;
     86                     this.cursorImage = new Bitmap(cursorWidth, cursorHeight);
     87                     Rectangle bounds = new Rectangle(source.Width >= 2 * e.X ? cursorWidth - source.Width : 0, source.Height >= 2 * e.Y ? cursorHeight - source.Height : 0, source.Width, source.Height);
     88                     source.DrawToBitmap(cursorImage, bounds);
     89                     this.defaultCursor.Draw(Graphics.FromImage(this.cursorImage), new Rectangle(bounds.X + e.X, bounds.Y + e.Y, this.defaultCursor.Size.Width, this.defaultCursor.Size.Height));
     90                     this.ChangeAlpha(cursorImage, bounds);
     91                     this.cursor = new Cursor(this.cursorImage.GetHicon());
     92                     source.Cursor = this.cursor;
     93                 }
     94             }
     95         }
     96 
     97         private void OnSourceMouseUp(object sender, MouseEventArgs e)
     98         {
     99             if (this.isMovePrepared)
    100             {
    101                 var source = sender as Source;
    102                 if (source == null)
    103                 {
    104                     return;
    105                 }
    106 
    107                 if (this.cursor != null)
    108                 {
    109                     source.Cursor = defaultCursor;
    110                     this.cursorImage.Dispose();
    111                     this.cursorImage = null;
    112                     this.cursor.Dispose();
    113                     this.cursor = null;
    114                 }
    115 
    116                 this.isMovePrepared = false;
    117                 source.Capture = false;
    118                 // find the target control where the source control is dropped by the mouse up location.
    119                 Target target = null;
    120                 var mouseLocation = source.PointToScreen(e.Location);
    121                 foreach (var item in this.targets)
    122                 {
    123                     Point offset = item.PointToScreen(new Point(0, 0));
    124                     Rectangle bounds = new Rectangle(offset, item.Size);
    125                     if (bounds.Contains(mouseLocation))
    126                     {
    127                         target = item;
    128                         break;
    129                     }
    130                 }
    131 
    132                 if (target != null && this.dropCallBack != null)
    133                 {
    134                     this.dropCallBack(source, target);
    135                 }
    136             }
    137         }
    138 
    139         private void ChangeAlpha(Bitmap img, Rectangle bounds)
    140         {
    141             for (int x = bounds.Left; x < bounds.Right; x++)
    142             {
    143                 for (int y = bounds.Top; y < bounds.Bottom; y++)
    144                 {
    145                     Color orgColor = img.GetPixel(x, y);
    146                     img.SetPixel(x, y, Color.FromArgb(150, orgColor.R, orgColor.G, orgColor.B));
    147                 }
    148             }
    149         }
    150     }
    DragDropController

    这个类可以实现将拖拽source到targets中任意一个控件过程中,鼠标跟随一张透明的source控件的图片。下面是使用该类的方法:

     1     public partial class Form1 : Form
     2     {
     3         private DragDropController<PictureBox, PictureBox> dragDropTest;
     4 
     5         public Form1()
     6         {
     7             InitializeComponent();
     8             this.dragDropTest = new DragDropController<PictureBox, PictureBox>(new List<PictureBox>() { this.pictureBox1, this.pictureBox2 }, new List<PictureBox>() { this.pictureBox3, this.pictureBox4 }, this.DropCallBack);
     9             this.dragDropTest.EnableDragDrop();
    10         }
    11 
    12         private void DropCallBack(PictureBox source, PictureBox target)
    13         {
    14             target.Image = source.Image;
    15         }
    16     }
    Demo

    该方法实现从pictureBox1拖拽图片到pictureBox2或pictureBox3中的效果。

    主要发现一个问题:在开始拖拽的时候,Cursor图片的生成比较复杂,性能似乎比较低,不知是否有优化之法。

  • 相关阅读:
    js 字符串转化成数字:(实例:用正则检测大于0的正数,最多保留4位小数)
    SQL Server 2008 阻止保存要求重新创建表的更改问题的设置方法
    Entity Framework学习二:定义数据结构
    Entity Framework学习一:在.net类基础上创建新数据库
    Create Primary Key using Entity Framework Code First
    MVC缓存(转载)
    不错的博文地址
    read xml test
    xml读取类
    VS2010+ASP.NET MVC4+EF4+JqueryEasyUI+Oracle项目开发(转载)
  • 原文地址:https://www.cnblogs.com/haihai1203/p/3204102.html
Copyright © 2020-2023  润新知