一起谈.NET技术,Silverlight 中用鼠标同时选中和移动多个控件

  在设计 WinForm 程序时,我们可以很方便的同时选择窗体上的多个控件来调整控件的位置。在 Silverlight 应用程序中有时我们也想实现同样的功能,以提供更好的用户体验。本文将要介绍的就是在 Silverlight 程序中实现同时选中和移动多个控件。

  1、实现鼠标拖动选择时显示所选区域

  2、移动所选区域时同时移动在该区域内的控件

  要实现鼠标拖动选择时显示所选区域功能,可以在鼠标拖动时在 Canvas 容器中动态添加一个 Rectangle 来显示类似在 Windows 资源管理器拖动选择文件时的选择框。实现前面所述功能的操作:在 Canvas 容器中按下鼠标左键并拖动鼠标来修改选择区域,选定目标区域后松开鼠标按键,这时显示一个表示所选区域的矩形选框。由实现的操作可知,我们需要在鼠标左键按下时在 Canvas 容器中添加一个矩形框,然后在鼠标移动时根据鼠标的位置更新矩形框的大小,最后在鼠标左键弹起显示最终的选择区域并查找出在选择区域中的控件。

 
  
private Point origPoint; /* 鼠标点击的位置 */
private Rectangle rect; /* 选择的区域 */
private Rect selectedRect; /* 选择的矩形区域 */
private bool isMultipleSelected;
private List < FrameworkElement > selectedElements = new List < FrameworkElement > ();

public MainPage()
{
InitializeComponent();

this .rootCanvas.MouseLeftButtonDown += Handle_MouseLeftButtonDown;
}

private void Handle_MouseLeftButtonDown( object sender, MouseButtonEventArgs e)
{
if (e.OriginalSource is Canvas)
{
if (rect != null )
{
isMultipleSelected
= false ;

rootCanvas.Children.Remove(rect);
rect
= null ;
}
else
{
isMultipleSelected
= true ;

rect
= new Rectangle();
origPoint
= e.GetPosition(rootCanvas);

rootCanvas.Children.Add(rect);
rect.SetValue(Canvas.LeftProperty, origPoint.X);
rect.SetValue(Canvas.TopProperty, origPoint.Y);

rect.Fill
= new SolidColorBrush(Colors.LightGray);
rect.Stroke
= new SolidColorBrush(Colors.Black);
rect.StrokeThickness
= 3 ;
rect.Opacity
= . 5 ;

rect.MouseLeftButtonDown
+= Handle_MouseLeftButtonDown;

rootCanvas.MouseMove
+= Handle_MouseMove;
rootCanvas.MouseLeftButtonUp
+= Handle_MouseLeftButtonUp;
}
}
else if (e.OriginalSource is Rectangle)
{
isMultipleSelected
= false ;

origPoint
= e.GetPosition(rootCanvas);

rect.MouseMove
+= Handle_MouseMove;
rect.MouseLeftButtonUp
+= Handle_MouseLeftButtonUp;
rect.CaptureMouse();

/*
* 查找在选择范围内的控件
*
*/

double rLeft = ( double )rect.GetValue(Canvas.LeftProperty);
double rTop = ( double )rect.GetValue(Canvas.TopProperty);

foreach (FrameworkElement item in rootCanvas.Children)
{
double cLeft = ( double )item.GetValue(Canvas.LeftProperty);
double cTop = ( double )item.GetValue(Canvas.TopProperty);

Rect rc1
= new Rect(selectedRect.X, selectedRect.Y, selectedRect.Width, selectedRect.Height);
Rect rc2
= new Rect(cLeft, cTop, item.ActualWidth, item.ActualHeight);
rc1.Intersect(rc2);
/* 判断控件所在的矩形区域与选择的矩形区域是否相交 */
if (rc1 != Rect.Empty)
{
if ( ! selectedElements.Contains(item))
selectedElements.Add(item);
}
}
}
}

private void Handle_MouseLeftButtonUp( object sender, MouseButtonEventArgs e)
{
if (isMultipleSelected)
{
/* 所选区域的矩形 */
selectedRect
= new Rect(( double )rect.GetValue(Canvas.LeftProperty),
(
double )rect.GetValue(Canvas.TopProperty), rect.Width, rect.Height);

rootCanvas.MouseLeftButtonUp
-= Handle_MouseLeftButtonUp;
rootCanvas.MouseMove
-= Handle_MouseMove;
}
}

private void Handle_MouseMove( object sender, MouseEventArgs e)
{
if (isMultipleSelected)
{
Point curPoint
= e.GetPosition(rootCanvas);
if (curPoint.X > origPoint.X)
{
rect.Width
= curPoint.X - origPoint.X;
}
if (curPoint.X < origPoint.X)
{
rect.SetValue(Canvas.LeftProperty, curPoint.X);
rect.Width
= origPoint.X - curPoint.X;
}
if (curPoint.Y > origPoint.Y)
{
rect.Height
= curPoint.Y - origPoint.Y;
}
if (curPoint.Y < origPoint.Y)
{
rect.SetValue(Canvas.TopProperty, curPoint.Y);
rect.Height
= origPoint.Y - curPoint.Y;
}
}
}

  在上面的代码中首先定义了几个要用到的变量:origPoint 用来保存鼠标点击时的位置,在动态修改矩形选框和移动控件时会用到;rect 显示矩形选框;selectedRect 矩形选框的矩形大小;isMultipleSelected 标识是否是拖动鼠标进行选择;selectedElements 保存在选择区域中的控件。

  在鼠标左键单击事件中,先判断是在 Canvas 容器中单击的还是在 Rectangle 中单击的,注意我们是用 e.OriginalSource 来判断引发事件的对象的,因为 Canvas 和 Rectangle 都要处理鼠标左键单击事件,在 Rectangle 上单击时同时会触发 Canvas 上的单击事件,因此用 sender 来判断引发事件的对象是不准确的。如果是在 Canvas 中进行的单击,先判断 rect 变量是否为 null,如果 rect 不为 null 说明之前已进行过选择或单击,则在 Canvas 中移除 rect 并将 rect 设为 null,将 isMultipleSelected 设为 false;如果 rect 为 null,则将 isMultipleSelected 设为 true 表示当前操作是在进行选择,接着新建一个 Rectangle 并记下鼠标点击的位置,然后将新建的 rect 添加到 Canvas 中。如果是在 Rectangle 上进行的单击,则表示已经执行完选择操作了要进行移动选择区域的操作,首先记下鼠标点击的位置并附加相应的处理事件,然后通过遍历 Canvas 的子控件来找出在选择区域的所有控件并保存到selectedElements 中。在判断控件是否在选择区域中时用的是 Rect 的 Intersect (判断两个矩形是否相交) 方法进行判断的,开始想到的是判断控件所在的矩形的四个顶点和选择区域的四个顶点的位置关系,网上打了一下很多人也是这么做的,后来想到 WinForm 中的 Rectangle 中有 Intersect 这个方法,Silverlight 中有没有呢,后来发现 Silverlight 中的 Rectangle 没有 Intersect 这个方法而 Rect 有这个方法,这就是代码中为什么要用 selectedRect 这个变量保存选择区域所在的矩形。

  在鼠标左键的弹起事件中,首先判断是不是在进行选择,如果是则记下选择区域所在的矩形。在鼠标移动事件中,如果是在进行选择,根据鼠标当前所在的位置更新 rect 选择区域的大小。

  到这里我们已经完成了建立选择区域的操作,运行结果如下图所示:选择区域  接下来实现移动选择区域时同时对选择的控件进行移动。

  实现移动选择区域时现时对选择的控件进行移动的操作是:鼠标在选择区域上按下,接着移动鼠标,在移动鼠标时更新选择区域的位置同时也更新选择的控件的位置。我们需要处理的事件是 Rectangle 的鼠标单击、移动和弹起事件。

 
  
private bool isMouseCaptured;

  首先新建一个 isMouseCaptured 变量,用来标识鼠标是否选中了矩形选框 rect,在 Canvas 的单击事件中将 isMouseCaptured 设为 false,在 Rectangle 的单击事件中将 isMouseCaptured 设为 true 。

  选择区域的单击事件的处理代码在上面的代码中已经有了,移动事件和弹起事件的处理代码如下:

 
  
// 鼠标移动事件处理代码 加入Handle_MouseMove中
if (isMouseCaptured)
{
double deltaV = e.GetPosition(rootCanvas).Y - origPoint.Y;
double deltaH = e.GetPosition(rootCanvas).X - origPoint.X;
double newTop = deltaV + ( double )rect.GetValue(Canvas.TopProperty);
double newLeft = deltaH + ( double )rect.GetValue(Canvas.LeftProperty);

foreach (var item in selectedElements)
{
double cLeft = ( double )item.GetValue(Canvas.LeftProperty);
double cTop = ( double )item.GetValue(Canvas.TopProperty);

item.SetValue(Canvas.LeftProperty, deltaH
+ cLeft);
item.SetValue(Canvas.TopProperty, deltaV
+ cTop);
}

rect.SetValue(Canvas.TopProperty, newTop);
rect.SetValue(Canvas.LeftProperty, newLeft);

origPoint
= e.GetPosition(rootCanvas);
}

// 鼠标左键弹起事件处理代码 加入Handle_MouseLeftButtonUp中
if (isMouseCaptured)
{
selectedElements.Clear();
rect.ReleaseMouseCapture();
isMouseCaptured
= false ;

rootCanvas.Children.Remove(rect);
rect
= null ;
}

  在鼠标移动事件中我们根据鼠标当前的位置更新选择区域的位置和选择的控件的位置,在鼠标左键弹起事件中将记录的选择的控件清除并把选择区域 rect 从 Canvas 容器中移除。

  到这里我们已经实现了用鼠标现时选择和移动多个控件的操作。示例代码下载:http://zdd.me/myfiles

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值