WPF下的仿QQ图片查看器
本例中的大图模式使用图片控件展示,监听控件的鼠标滚轮事件和移动事件,缩略图和鹰眼模式采用装饰器对象IndicatorObject和Canvas布局。百分比使用一个定时器,根据图片的放大倍数计算具体的数值显示。
首先看看效果图:

以下开始绘制图片 定义缩略图上白色的矩形,这其实是一个Indicator,它的外围是一个Canvas,然后缩略图是一个Image控件
internal class IndicatorObject : ContentControl
{
private MaskCanvas canvasOwner; public IndicatorObject(MaskCanvas canvasOwner)
{
this.canvasOwner = canvasOwner;
} static IndicatorObject()
{
var ownerType = typeof(IndicatorObject); FocusVisualStyleProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(null));
DefaultStyleKeyProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(ownerType));
MinWidthProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(5.0));
MinHeightProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(5.0));
} public void Move(System.Windows.Point offset)
{
var x = Canvas.GetLeft(this) + offset.X;
var y = Canvas.GetTop(this) + offset.Y; x = x < ? : x;
y = y < ? : y; x = Math.Min(x, this.canvasOwner.Width - this.Width);
y = Math.Min(y, this.canvasOwner.Height - this.Height); Canvas.SetLeft(this, x);
Canvas.SetTop(this, y); canvasOwner.UpdateSelectionRegion(new Rect(x, y, Width, Height), true);
} }
Indicator
查看位置所在的矩形定义好了,然后开始定义外围的Canvas,这个作用是可以在Canvas上选中移动到查看的位置
public class MaskCanvas : Canvas
{
public MaskCanvas()
{
Loaded += OnLoaded;
} public System.Windows.Media.Brush SelectionBorderBrush = new SolidColorBrush(System.Windows.Media.Color.FromArgb(, , , ));
public Thickness SelectionBorderThickness = new Thickness(); public System.Windows.Media.Brush MaskWindowBackground = new SolidColorBrush(System.Windows.Media.Color.FromArgb(, , , )); public event EventHandler<LoactionArgs> LoationChanged; private void OnLoaded(object sender, RoutedEventArgs e)
{
maskRectLeft.Fill = maskRectRight.Fill = maskRectTop.Fill = maskRectBottom.Fill = MaskWindowBackground; SetLeft(maskRectLeft, );
SetTop(maskRectLeft, );
SetRight(maskRectRight, );
SetTop(maskRectRight, );
SetTop(maskRectTop, );
SetBottom(maskRectBottom, );
maskRectLeft.Height = ActualHeight; Children.Add(maskRectLeft);
Children.Add(maskRectRight);
Children.Add(maskRectTop);
Children.Add(maskRectBottom); selectionBorder.Stroke = SelectionBorderBrush;
selectionBorder.StrokeThickness = ; Children.Add(selectionBorder); indicator = new IndicatorObject(this);
indicator.Visibility = System.Windows.Visibility.Hidden;
Children.Add(indicator); CompositionTarget.Rendering += OnCompositionTargetRendering; } private void UpdateSelectionBorderLayout()
{
if (!selectionRegion.IsEmpty)
{
SetLeft(selectionBorder, selectionRegion.Left);
SetTop(selectionBorder, selectionRegion.Top);
selectionBorder.Width = selectionRegion.Width;
selectionBorder.Height = selectionRegion.Height;
}
} private void UpdateMaskRectanglesLayout()
{
var actualHeight = ActualHeight;
var actualWidth = ActualWidth; if (selectionRegion.IsEmpty)
{
SetLeft(maskRectLeft, );
SetTop(maskRectLeft, );
maskRectLeft.Width = actualWidth;
maskRectLeft.Height = actualHeight; maskRectRight.Width = maskRectRight.Height = maskRectTop.Width = maskRectTop.Height = maskRectBottom.Width = maskRectBottom.Height = ;
}
else
{
var temp = selectionRegion.Left;
if (maskRectLeft.Width != temp)
{
maskRectLeft.Width = temp < ? : temp; //Math.Max(0, selectionRegion.Left);
} temp = ActualWidth - selectionRegion.Right;
if (maskRectRight.Width != temp)
{
maskRectRight.Width = temp < ? : temp; //Math.Max(0, ActualWidth - selectionRegion.Right);
} if (maskRectRight.Height != actualHeight)
{
maskRectRight.Height = actualHeight;
} SetLeft(maskRectTop, maskRectLeft.Width);
SetLeft(maskRectBottom, maskRectLeft.Width); temp = actualWidth - maskRectLeft.Width - maskRectRight.Width;
if (maskRectTop.Width != temp)
{
maskRectTop.Width = temp < ? : temp; //Math.Max(0, ActualWidth - maskRectLeft.Width - maskRectRight.Width);
} temp = selectionRegion.Top;
if (maskRectTop.Height != temp)
{
maskRectTop.Height = temp < ? : temp; //Math.Max(0, selectionRegion.Top);
} maskRectBottom.Width = maskRectTop.Width; temp = actualHeight - selectionRegion.Bottom;
if (maskRectBottom.Height != temp)
{
maskRectBottom.Height = temp < ? : temp; //Math.Max(0, ActualHeight - selectionRegion.Bottom);
}
}
} #region Fileds & Props
private Rect selectionRegion = Rect.Empty;
private bool isMaskDraging;
public bool MoveState = false;
private IndicatorObject indicator;
private System.Windows.Point? selectionStartPoint;
private System.Windows.Point? selectionEndPoint; private readonly System.Windows.Shapes.Rectangle selectionBorder = new System.Windows.Shapes.Rectangle(); private readonly System.Windows.Shapes.Rectangle maskRectLeft = new System.Windows.Shapes.Rectangle();
private readonly System.Windows.Shapes.Rectangle maskRectRight = new System.Windows.Shapes.Rectangle();
private readonly System.Windows.Shapes.Rectangle maskRectTop = new System.Windows.Shapes.Rectangle();
private readonly System.Windows.Shapes.Rectangle maskRectBottom = new System.Windows.Shapes.Rectangle(); public System.Drawing.Size? DefaultSize
{
get;
set;
}
#endregion #region Mouse Managment private bool IsMouseOnThis(RoutedEventArgs e)
{
return e.Source.Equals(this) || e.Source.Equals(maskRectLeft) || e.Source.Equals(maskRectRight) || e.Source.Equals(maskRectTop) || e.Source.Equals(maskRectBottom);
} protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
indicator.Visibility = System.Windows.Visibility.Visible; if (e.Source.Equals(indicator))
{
HandleIndicatorMouseDown(e);
}
base.OnMouseLeftButtonDown(e);
} protected override void OnMouseMove(MouseEventArgs e)
{
if (IsMouseOnThis(e))
{
UpdateSelectionRegion(e, UpdateMaskType.ForMouseMoving); e.Handled = true;
}
base.OnMouseMove(e);
} protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
if (IsMouseOnThis(e))
{
UpdateSelectionRegion(e, UpdateMaskType.ForMouseLeftButtonUp);
FinishShowMask();
}
base.OnMouseLeftButtonUp(e);
} protected override void OnMouseRightButtonUp(MouseButtonEventArgs e)
{
indicator.Visibility = Visibility.Collapsed;
selectionRegion = Rect.Empty;
selectionBorder.Width = selectionBorder.Height = ;
// ClearSelectionData();
UpdateMaskRectanglesLayout(); base.OnMouseRightButtonUp(e);
} internal void HandleIndicatorMouseDown(MouseButtonEventArgs e)
{
MoveState = true;
} internal void HandleIndicatorMouseUp(MouseButtonEventArgs e)
{
MoveState = false;
} private void PrepareShowMask(System.Drawing.Point mouseLoc)
{
indicator.Visibility = Visibility.Collapsed;
selectionBorder.Visibility = Visibility.Visible; } private void UpdateSelectionRegion()
{
var startPoint = new System.Drawing.Point(,);
var endPoint = new System.Drawing.Point(, );
var sX = startPoint.X;
var sY = startPoint.Y;
var eX = endPoint.X;
var eY = endPoint.Y; var deltaX = eX - sX;
var deltaY = eY - sY; if (Math.Abs(deltaX) >= SystemParameters.MinimumHorizontalDragDistance ||
Math.Abs(deltaX) >= SystemParameters.MinimumVerticalDragDistance)
{ double x = sX < eX ? sX : eX;//Math.Min(sX, eX);
double y = sY < eY ? sY : eY;//Math.Min(sY, eY);
double w = deltaX < ? -deltaX : deltaX;//Math.Abs(deltaX);
double h = deltaY < ? -deltaY : deltaY;//Math.Abs(deltaY); selectionRegion = new Rect(x, y, w, h);
}
else
{
selectionRegion = new Rect(startPoint.X, startPoint.Y, DefaultSize.Value.Width, DefaultSize.Value.Height);
}
} private void UpdateSelectionRegion(MouseEventArgs e, UpdateMaskType updateType)
{
if (updateType == UpdateMaskType.ForMouseMoving && e.LeftButton != MouseButtonState.Pressed)
{
selectionStartPoint = null;
} if (selectionStartPoint.HasValue)
{
selectionEndPoint = e.GetPosition(this); var startPoint = (System.Windows.Point)selectionEndPoint;
var endPoint = (System.Windows.Point)selectionStartPoint;
var sX = startPoint.X;
var sY = startPoint.Y;
var eX = endPoint.X;
var eY = endPoint.Y; var deltaX = eX - sX;
var deltaY = eY - sY; if (Math.Abs(deltaX) >= SystemParameters.MinimumHorizontalDragDistance ||
Math.Abs(deltaX) >= SystemParameters.MinimumVerticalDragDistance)
{
isMaskDraging = true; double x = sX < eX ? sX : eX;//Math.Min(sX, eX);
double y = sY < eY ? sY : eY;//Math.Min(sY, eY);
double w = deltaX < ? -deltaX : deltaX;//Math.Abs(deltaX);
double h = deltaY < ? -deltaY : deltaY;//Math.Abs(deltaY); selectionRegion = new Rect(x, y, w, h);
}
else
{
if (DefaultSize.HasValue && updateType == UpdateMaskType.ForMouseLeftButtonUp)
{
isMaskDraging = true; selectionRegion = new Rect(startPoint.X, startPoint.Y, DefaultSize.Value.Width, DefaultSize.Value.Height);
}
else
{
isMaskDraging = false;
}
}
} UpdateIndicator(selectionRegion);
} internal void UpdateSelectionRegion(Rect region, bool flag = false)
{
selectionRegion = region;
UpdateIndicator(selectionRegion);
if (LoationChanged != null && flag)
{
LoationChanged(this, new LoactionArgs(region.Left/this.Width, region.Top/this.Height));
}
} private void FinishShowMask()
{
if (IsMouseCaptured)
{
ReleaseMouseCapture();
} if (isMaskDraging)
{ UpdateIndicator(selectionRegion); ClearSelectionData();
}
} private void ClearSelectionData()
{
isMaskDraging = false;
selectionBorder.Visibility = Visibility.Collapsed;
selectionStartPoint = null;
selectionEndPoint = null;
} private void UpdateIndicator(Rect region)
{
if (indicator == null)
return; if (region.Width < indicator.MinWidth || region.Height < indicator.MinHeight)
{
return;
}
indicator.Visibility = Visibility.Visible;
indicator.Width = region.Width;
indicator.Height = region.Height;
SetLeft(indicator, region.Left);
SetTop(indicator, region.Top); } private Rect GetIndicatorRegion()
{
return new Rect(GetLeft(indicator), GetTop(indicator), indicator.ActualWidth, indicator.ActualHeight);
} #endregion #region Render private void OnCompositionTargetRendering(object sender, EventArgs e)
{
UpdateSelectionBorderLayout();
UpdateMaskRectanglesLayout();
} #endregion #region inner types private enum UpdateMaskType
{
ForMouseMoving,
ForMouseLeftButtonUp
} #endregion }
Canvas
缩略图很简单,按照比例缩放图片加载上即可
thumbImage = m_Bitmap.GetThumbnailImage(thumbWidth, thumbHeight, null, IntPtr.Zero) as Bitmap; //thumbWidth指定宽,thumbHeight指定高度
ThumbnailImage
然后我们为大图加上监听事件ScrollChanged和MouseWheel 以及MouseLeftButtonDown、MouseLeftButtonUp、 MouseMove
ScrollChanged用来计算显示的滚动区域范围
if (e.ExtentHeight > e.ViewportHeight || e.ExtentWidth > e.ViewportWidth)
{
offsetX = (e.ExtentWidth - e.ViewportWidth) / ;
offsetY = (e.ExtentHeight - e.ViewportHeight) / ; svImg.ScrollToVerticalOffset(offsetY);
svImg.ScrollToHorizontalOffset(offsetX); } double timeH = svImg.ViewportHeight/ (svImg.ViewportHeight + svImg.ScrollableHeight);
double timeW = svImg.ViewportWidth / (svImg.ViewportWidth + svImg.ScrollableWidth); double w = thumbWidth * timeW;
double h = thumbHeight * timeH; double offsetx = ;
double offsety = ;
if (svImg.ScrollableWidth == )
{
offsetx = ;
}
else
{
offsetx = (w - thumbWidth) / svImg.ScrollableWidth * svImg.HorizontalOffset;
} if (svImg.ScrollableHeight == )
{
offsety = ;
}
else
{
offsety = (h - thumbHeight) / svImg.ScrollableHeight * svImg.VerticalOffset;
} Rect rect = new Rect( - offsetx, - offsety, w, h); mask.UpdateSelectionRegion(rect);
ScrollChanged
MouseWheel计算滚动比例
var mosePos = e.GetPosition(img);
scale = scale * (e.Delta > ? 1.2 : / 1.2);
scale = Math.Max(scale, 0.15);
scale = Math.Min(, scale);
this.txtZoom.Text = ((int)(scale * )).ToString();
img.Width = scale * imgWidth;
img.Height = scale * imgHeight;
offsetX = svImg.ScrollableWidth / ;
offsetY = svImg.ScrollableHeight / ;
MouseWheel
MouseLeftButtonDown后三个事件在移动图片时使用
以上大部分的工作已经做完了,然后我们加入一个定时器的功能,调节显示百分比的时间。加上一个Timer类即可。
当然在ScrolChanged里面我们加入了鹰眼监控,细心的朋友可以在事件里面看到。
WPF下的仿QQ图片查看器的更多相关文章
- wpf 仿QQ图片查看器
参考博客 WPF下的仿QQ图片查看器 wpf图片查看器,支持鼠标滚动缩放拖拽 实现效果 主要参考的WPF下的仿QQ图片查看器,原博主只给出了部分代码. 没有完成的部分 1.右下角缩略图是原图不是缩略图 ...
- jquery图片查看插件,支持旋转、放大、缩小、拖拽、缩略图(仿qq图片查看)
最近做了一个jquery图片查看的插件,目的是能精确查看图片的详情,插件支持图片旋转.放大.缩小.拖拽.缩略图显示,界面效果是按照window的qq查看图片功能写的,当然不尽相同. 具体功能: 1. ...
- 图片特效-仿 iPhone 图片查看器效果
—————————————————————— <script type="text/javascript"> var arr = ...
- jQuery 图片查看插件 Magnify 开发简介(仿 Windows 照片查看器)
前言 因为一些特殊的业务需求,经过一个多月的蛰伏及思考,我开发了这款 jQuery 图片查看器插件 Magnify,它实现了 Windows 照片查看器的所有功能,比如模态窗的拖拽.调整大小.最大化, ...
- jQuery 插件 Magnify 开发简介(仿 Windows 照片查看器)
前言 因为一些特殊的业务需求,经过一个多月的蛰伏及思考,我开发了这款 jQuery 图片查看器插件 Magnify,它实现了 Windows 照片查看器的所有功能,比如模态窗的拖拽.调整大小.最大化, ...
- wpf图片查看器,支持鼠标滚动缩放拖拽
最近项目需要,要用到一个图片查看器,类似于windows自带的图片查看器那样,鼠标滚动可以缩放,可以拖拽图片,于是就写了这个简单的图片查看器. 前台代码: <Window x:Class=&qu ...
- 发布两款JQ小插件(图片查看器 + 分类选择器),开源
图片查看器,github地址:https://github.com/VaJoy/imgViewer 效果如下: 这款当初大概写了2小时,有点匆忙地赶出来的,使用的接口很简单: $.bindViewer ...
- 用JQ仿造礼德财富网的图片查看器
现在就职于一家P2P平台,自然也会关注同行其它网站的前端技术,今天要仿造的是礼德内页的一个图片查看器效果.不过说白了,无论人人贷也好礼德财富也好,很多地方的前端都做的不尽如人意,比如忽略细节.缺乏交互 ...
- Objective-C ,ios,iphone开发基础:快速实现一个简单的图片查看器
新建一个single view 工程: 关闭ARC , 在.xib视图文件上拖放一个UIImageView 两个UIButton ,一个UISlider ,布局如图. 并为他们连线, UIImage ...
随机推荐
- (转)MySQL索引原理及慢查询优化
转自美团技术博客,原文地址:http://tech.meituan.com/mysql-index.html 建索引的一些原则: 1.最左前缀匹配原则,非常重要的原则,mysql会一直向右匹配直到遇到 ...
- RDS MySQL 空间问题的原因和解决
来源:https://help.aliyun.com/knowledge_detail/41739.html RDS MySQL 空间问题的原因和解决 更新时间:2016-07-22 17:20:14 ...
- tyvj1005 采药
描述 辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师.为此,他想拜附近最有威望的医师为师.医师为了判断他的资质,给他出了一个难题.医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞 ...
- [Data Structure & Algorithm] 八大排序算法
排序有内部排序和外部排序之分,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存.我们这里说的八大排序算法均为内部排序. 下图为排序 ...
- mysql的DISABLE/ENABLE KEYS
有一个表 tbl1 的结构如下: CREATE TABLE `tbl1` ( `id` int(10) unsigned NOT NULL auto_increment, `name` char(20 ...
- Linux下c开发 之 线程通信(转)
Linux下c开发 之 线程通信(转) 1.Linux“线程” 进程与线程之间是有区别的,不过Linux内核只提供了轻量进程的支持,未实现线程模型.Linux是一种“多进程单线程”的操作系统.Linu ...
- js 获取元素宽高
可以用源生js的.offsetHeight .offsetWidth属性 document.getElementById("temp_form").offsetHeight // ...
- javascript的window.ActiveXObject对象,区别浏览器的方法
(window.ActiveXObject)的作用,用来判断浏览器是否支持ActiveX控件,如果支持ActiveX控件,我们可以利用var xml=new ActiveXObject("M ...
- MyBatis的初始化方式
1. 加载配置文件 public static void main(String[] args) throws IOException { //mybatis的配置文件 String resource ...
- 创建新用户,连接Oracle数据库
1.sys用户是最高管理员用户,那我们就用这个sys用户登录oracle: