zoukankan      html  css  js  c++  java
  • 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 < 0 ? 0 : x;
                y = y < 0 ? 0 : 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(255, 255, 255, 255));
            public Thickness SelectionBorderThickness = new Thickness(1);
    
            public System.Windows.Media.Brush MaskWindowBackground = new SolidColorBrush(System.Windows.Media.Color.FromArgb(5, 0, 0, 0));
    
            public event EventHandler<LoactionArgs> LoationChanged;
    
            private void OnLoaded(object sender, RoutedEventArgs e)
            {
               maskRectLeft.Fill = maskRectRight.Fill = maskRectTop.Fill = maskRectBottom.Fill = MaskWindowBackground;
    
                SetLeft(maskRectLeft, 0);
                SetTop(maskRectLeft, 0);
                SetRight(maskRectRight, 0);
                SetTop(maskRectRight, 0);
                SetTop(maskRectTop, 0);
                SetBottom(maskRectBottom, 0);
                maskRectLeft.Height = ActualHeight;
    
                Children.Add(maskRectLeft);
                Children.Add(maskRectRight);
                Children.Add(maskRectTop);
                Children.Add(maskRectBottom);
    
                selectionBorder.Stroke = SelectionBorderBrush;
                selectionBorder.StrokeThickness =  1;
             
                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, 0);
                    SetTop(maskRectLeft, 0);
                    maskRectLeft.Width = actualWidth;
                    maskRectLeft.Height = actualHeight;
    
                    maskRectRight.Width = maskRectRight.Height = maskRectTop.Width = maskRectTop.Height = maskRectBottom.Width = maskRectBottom.Height = 0;
                }
                else
                {
                    var temp = selectionRegion.Left;
                    if (maskRectLeft.Width != temp)
                    {
                        maskRectLeft.Width = temp < 0 ? 0 : temp; //Math.Max(0, selectionRegion.Left);
                    }
    
                    temp = ActualWidth - selectionRegion.Right;
                    if (maskRectRight.Width != temp)
                    {
                        maskRectRight.Width = temp < 0 ? 0 : 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 < 0 ? 0 : temp; //Math.Max(0, ActualWidth - maskRectLeft.Width - maskRectRight.Width);
                    }
    
                    temp = selectionRegion.Top;
                    if (maskRectTop.Height != temp)
                    {
                        maskRectTop.Height = temp < 0 ? 0 : temp; //Math.Max(0, selectionRegion.Top);
                    }
    
                    maskRectBottom.Width = maskRectTop.Width;
    
                    temp = actualHeight - selectionRegion.Bottom;
                    if (maskRectBottom.Height != temp)
                    {
                        maskRectBottom.Height = temp < 0 ? 0 : 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 = 0;
               // 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(0,0);
                var endPoint = new System.Drawing.Point(190, 130);
                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 < 0 ? -deltaX : deltaX;//Math.Abs(deltaX);
                    double h = deltaY < 0 ? -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 < 0 ? -deltaX : deltaX;//Math.Abs(deltaX);
                        double h = deltaY < 0 ? -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) / 2;
                    offsetY = (e.ExtentHeight - e.ViewportHeight) / 2;
    
                    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 = 0;
                double offsety = 0;
                if (svImg.ScrollableWidth == 0)
                {
                    offsetx = 0;
                }
                else
                {
                    offsetx = (w - thumbWidth) / svImg.ScrollableWidth * svImg.HorizontalOffset;
                }
    
                if (svImg.ScrollableHeight == 0)
                {
                    offsety = 0;
                }
                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 > 0 ? 1.2 : 1 / 1.2);
                scale = Math.Max(scale, 0.15);
                scale = Math.Min(16, scale);
                
                this.txtZoom.Text = ((int)(scale * 100)).ToString();
    
                img.Width = scale * imgWidth;
                img.Height = scale * imgHeight;
    
                offsetX = svImg.ScrollableWidth / 2;
                offsetY = svImg.ScrollableHeight / 2;
    MouseWheel

    MouseLeftButtonDown后三个事件在移动图片时使用

    MouseLeftButtonDown、MouseLeftButtonUp、MouseMove

    以上大部分的工作已经做完了,然后我们加入一个定时器的功能,调节显示百分比的时间。加上一个Timer类即可。

    当然在ScrolChanged里面我们加入了鹰眼监控,细心的朋友可以在事件里面看到。

  • 相关阅读:
    myeclipse 代码提示(alt+/)
    彻底解决mysql中文乱码
    Pycharm取消默认的右击运行unittest方法
    解决Ubuntu的root账号无法登录SSH问题-Permission denied, please try again.
    language support图标在哪里?怎么消失了?
    Ubuntu安装谷歌输入法或者搜狗
    最大流算法-ISAP
    WC2013-糖果公园
    bzoj4032-最短不公共子串
    bzoj1031-字符加密
  • 原文地址:https://www.cnblogs.com/yzp12sina/p/3916803.html
Copyright © 2011-2022 走看看