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 ...
随机推荐
- 自学 Java 怎么入门
自学 Java 怎么入门? 595赞同反对,不会显示你的姓名 给你推荐一个写得非常用心的Java基础教程:java-basic | 天码营 这个教程将Java的入门基础知识贯穿在一个实例中,逐 ...
- 安卓贴图源码--->单点触控.多点触控.类似in/百度魔图
效果如图: 类似in,百度魔图,的贴图功能 核心的地方:单/多点 旋转缩放后记录各个顶点小图标位置 引用这里 http://blog.csdn.net/xiaanming/article/detai ...
- ThinkPHP3.2.3整合smarty模板(一)
一.php模板引擎有哪些? 1.1 PHPLIB:一套古老且主流的模板引擎,直接在html中使用PHP变量进行编程: 1.2 Template Blocks:一款轻巧且速度非常快的PHP模板引擎,支持 ...
- (二)SQL Server分区创建过程
虽然分区有很多好处(一)SQL Server分区详解Partition,却不能随意使用:且不说分区管理的繁琐,只是跨分区带来的负面影响就需要我们好好分析是否有必要使用分区.一般分区创建的业务特点:用于 ...
- [Hadoop] 在Ubuntu系统上一步步搭建Hadoop(单机模式)
1 Hadoop的三种创建模式 单机模式操作是Hadoop的默认操作模式,当首次解压Hadoop的源码包时,Hadoop无法了解硬件安装环境,会保守地选择最小配置,即单机模式.该模式主要用于开发调试M ...
- Linux C popen()函数详解
表头文件 #include<stdio.h> 定义函数 FILE * popen( const char * command,const char * type); 函数说明 popen( ...
- H5项目常见问题及注意事项
Meta基础知识: H5页面窗口自动调整到设备宽度,并禁止用户缩放页面 //一.HTML页面结构 <meta name="viewport" content="wi ...
- r-cnn学习(四):train_faster_rcnn_alt_opt.py源码学习
论文看的云里雾里,希望通过阅读其代码来进一步了解. 参考:http://blog.csdn.net/sloanqin/article/details/51525692 首先是./tools/train ...
- NVelocity介绍,NVelocity中文手册文档及实例下载
NVelocity是什么velocity英音:[vi'lɔsiti]美音:[və'lɑsətɪ]近在做一个项目,客户要求有网站模板功能,能够自主编辑网站的风格,因为这个系统是为政府部门做子站系统,举个 ...
- nginx error_log 错误日志配置说明
nginx的error_log类型如下(从左到右:debug最详细 crit最少): [ debug | info | notice | warn | error | crit ] 例如:error_ ...