原文:
WPF C#截图功能 仿qq截图
3 自定义toolbar
先上效果图
源码下载地址:http://download.csdn.net/detail/candyvoice/9788099
描述:启动程序,点击窗口button,开始截图,鼠标左键按下拖动,选中任意区域,拖动过程中,左上角实时显示选中区域大小,拖动结束,鼠标左键抬起,出现右下角保存、取消、ok三个button。右键点击,取消当前选中,可以继续拖动鼠标左键进行截图。双击右键,退出截图功能。按键盘ESC键,可退出截图。
原理:说的通俗一些,就是在原有的界面上盖上一层Canvas,就是画布,然后在这个画布上画矩形,也就是填充矩形的四周,空出来的地方就变成矩形了,如下图。边框线,线上可拖动的小方框、顶角可拖动的小圆球,都是自定义的样式,可在代码的generic.xaml文件中看到具体的设计。
参考资料:http://www.cnblogs.com/zhouyinhui/archive/2010/08/20/1804762.html
这个楼主原理的细节方面已经说的很详细,大家可以仔细看看。
根据上述楼主的代码,主要修改了以下两个类。
MaskCanvas.cs就是操作画布的类,MaskWindow.cs就是截图窗口的类。左上角大小显示框,是一label;右下角的三个按钮是一个自定义的toolbar。
1 MaskCanvas.cs
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace RisCaptureLib
{
internal class MaskCanvas : Canvas
{
public delegate void FrameDrawEventHander(Rect rect);
public event FrameDrawEventHander OnMove;
public MaskCanvas()
{
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
//make the render effect same as SnapsToDevicePixels
//"SnapsToDevicePixels = true;" doesn't work on "OnRender"
//however, this maybe make some offset form the render target's origin location
//SetValue(RenderOptions.EdgeModeProperty, EdgeMode.Aliased);
//ini this
Cursor = BitmapCursor.CreateCrossCursor();
Background = Brushes.Transparent;
//ini mask rect
maskRectLeft.Fill = maskRectRight.Fill = maskRectTop.Fill = maskRectBottom.Fill = Config.MaskWindowBackground;
//these propeties(x, y...) will not changed
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);
//ini selection border
selectionBorder.Stroke = Config.SelectionBorderBrush;
selectionBorder.StrokeThickness = Config.SelectionBorderThickness.Left;
Children.Add(selectionBorder);
//ini indicator
indicator = new IndicatorObject(this);
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 IndicatorObject indicator;
private Point? selectionStartPoint;
private Point? selectionEndPoint;
private Rect selectionRegion = Rect.Empty;
private bool isMaskDraging;
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 Size? DefaultSize
{
get;
set;
}
public MaskWindow MaskWindowOwner
{
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)
{
if (selectionRegion != Rect.Empty)
return;
//mouse down on this self
if (IsMouseOnThis(e))
{
PrepareShowMask(Mouse.GetPosition(this));
}
//mouse down on indicator
else 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;
//委托调用
//Rect rec = OnMove();
if(OnMove != null)
{
if(selectionRegion !=null)
{
this.OnMove(selectionRegion);
}
}
}
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)
{
if(e.ClickCount>=2)
{
finishAction();
}
}
public void finishAction()
{
if (MaskWindowOwner != null)
{
MaskWindowOwner.ClipSnapshot(GetIndicatorRegion());
ClearSelectionData();
}
}
public System.Drawing.Bitmap GetSnapBitmap()
{
System.Drawing.Bitmap saveBitmap = null;
if (MaskWindowOwner != null)
{
Rect clipRegion = GetIndicatorRegion();
saveBitmap = MaskWindowOwner.CopyBitmapFromScreenSnapshot(clipRegion);
//close mask window
//Close();
//ClearSelectionData();
}
return saveBitmap;
}
private void PrepareShowMask(Point mouseLoc)
{
indicator.Visibility = Visibility.Collapsed;
selectionBorder.Visibility = Visibility.Visible;
selectionStartPoint = new Point?(mouseLoc);
if(!IsMouseCaptured)
{
CaptureMouse();
}
}
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 = (Point) selectionEndPoint;
var endPoint = (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;
}
}
}
}
internal void UpdateSelectionRegion(Rect region)
{
selectionRegion = region;
}
public Rect GetSelectionRegion()
{
return selectionRegion;
}
private void FinishShowMask()
{
if (IsMouseCaptured)
{
ReleaseMouseCapture();
}
if (isMaskDraging)
{
if (MaskWindowOwner != null)
{
MaskWindowOwner.OnShowMaskFinished(selectionRegion);
}
UpdateIndicator(selectionRegion);
ClearSelectionData();
}
}
private void ClearSelectionData()
{
isMaskDraging = false;
selectionBorder.Visibility = Visibility.Collapsed;
selectionStartPoint = null;
selectionEndPoint = null;
}
private void UpdateIndicator(Rect region)
{
if(region.Width<indicator.MinWidth || region.Height<indicator.MinHeight)
{
return;
}
indicator.Width = region.Width;
indicator.Height = region.Height;
SetLeft(indicator, region.Left);
SetTop(indicator, region.Top);
indicator.Visibility = Visibility.Visible;
}
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
}
}
using System.Drawing;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Controls;
using System;
namespace RisCaptureLib
{
internal class MaskWindow : Window
{
private MaskCanvas innerCanvas;
private Bitmap screenSnapshot;
private Timer timeOutTimmer;
private readonly ScreenCaputre screenCaputreOwner;
//截图显示尺寸label
System.Windows.Controls.Label label = null;
//截图显示按键
ToolBarControl toolBarContrl = null;
//截图保存图片
private System.Drawing.Bitmap m_bmpLayerCurrent;
public MaskWindow(ScreenCaputre screenCaputreOwner)
{
this.screenCaputreOwner = screenCaputreOwner;
Ini();
innerCanvas.OnMove += DrawShowSize;
}
private void Ini()
{
//ini normal properties
//Topmost = true;
WindowStyle = WindowStyle.None;
ResizeMode = ResizeMode.NoResize;
ShowInTaskbar = false;
//set bounds to cover all screens
var rect = SystemInformation.VirtualScreen;
Left = rect.X;
Top = rect.Y;
Width = rect.Width;
Height = rect.Height;
//set background
screenSnapshot = HelperMethods.GetScreenSnapshot();
if (screenSnapshot != null)
{
var bmp = screenSnapshot.ToBitmapSource();
bmp.Freeze();
Background = new ImageBrush(bmp);
}
//ini canvas
innerCanvas = new MaskCanvas
{
MaskWindowOwner = this
};
Content = innerCanvas;
}
protected override void OnMouseDown(MouseButtonEventArgs e)
{
base.OnMouseDown(e);
//鼠标右键双击取消
if(e.RightButton == MouseButtonState.Pressed && e.ClickCount>=2)
{
CancelCaputre();
}
CreatLabel(e.GetPosition(innerCanvas));
label.Visibility = Visibility.Visible;
if (toolBarContrl != null)
{
toolBarContrl.Visibility = Visibility.Hidden;
}
}
protected override void OnMouseMove(System.Windows.Input.MouseEventArgs e)
{
base.OnMouseMove(e);
if(timeOutTimmer != null && timeOutTimmer.Enabled)
{
timeOutTimmer.Stop();
timeOutTimmer.Start();
}
//设置左上角label和右下角toolbar鼠标跟随
Rect temRect = innerCanvas.GetSelectionRegion();
if(temRect == Rect.Empty)
{
return;
}
label.Content = "选中区域大小:" + temRect.Width + "×" + temRect.Height + "宽:" + temRect.Width + "高:" + temRect.Height;
if(label != null)
{
Canvas.SetLeft(label, temRect.X);
Canvas.SetTop(label, temRect.Y - 25);
}
if (toolBarContrl != null)
{
Canvas.SetLeft(toolBarContrl, temRect.X + temRect.Width - 75);
Canvas.SetTop(toolBarContrl, temRect.Y + temRect.Height);
}
}
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
CreatToolBar(e.GetPosition(innerCanvas));
toolBarContrl.Visibility = Visibility.Visible;
}
//创建提示选中区域大小控件
private void CreatLabel(System.Windows.Point location)
{
if (label == null)
{
label = new System.Windows.Controls.Label();
innerCanvas.Children.Add(label);
}
label.Content = GetLabelContent();
label.Height = 25;
Canvas.SetLeft(label, location.X);
Canvas.SetTop(label, location.Y - 25);
}
private void CreatToolBar(System.Windows.Point location)
{
if (toolBarContrl == null)
{
toolBarContrl = new ToolBarControl();
innerCanvas.Children.Add(toolBarContrl);
Canvas.SetLeft(toolBarContrl, location.X - 75);
Canvas.SetTop(toolBarContrl, location.Y);
}
toolBarContrl.OnOK += OKAction;
toolBarContrl.OnCancel += CancelAction;
toolBarContrl.OnSaveCapture += SaveCaptureAction;
}
private string GetLabelContent()
{
string strContent = "";
return strContent;
}
protected override void OnKeyDown(System.Windows.Input.KeyEventArgs e)
{
base.OnKeyDown(e);
if(e.Key == Key.Escape)
{
CancelCaputre();
}
}
private void CancelCaputre()
{
Close();
screenCaputreOwner.OnScreenCaputreCancelled(null);
}
internal void OnShowMaskFinished(Rect maskRegion)
{
}
internal void ClipSnapshot(Rect clipRegion)
{
BitmapSource caputredBmp = CopyFromScreenSnapshot(clipRegion);
if (caputredBmp != null)
{
screenCaputreOwner.OnScreenCaputred(null, caputredBmp);
}
//close mask window
Close();
}
internal BitmapSource CopyFromScreenSnapshot(Rect region)
{
if (region.Width.Equals(0.0) || region.Height.Equals(0.0))
{
return null;
}
var sourceRect = region.ToRectangle();
var destRect = new Rectangle(0, 0, sourceRect.Width, sourceRect.Height);
if (screenSnapshot != null)
{
var bitmap = new Bitmap(sourceRect.Width, sourceRect.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using (Graphics g = Graphics.FromImage(bitmap))
{
g.DrawImage(screenSnapshot, destRect, sourceRect, GraphicsUnit.Pixel);
}
return bitmap.ToBitmapSource();
}
return null;
}
private void SaveCaptureAction()
{
m_bmpLayerCurrent = innerCanvas.GetSnapBitmap();
if(m_bmpLayerCurrent == null)
{
return;
}
System.Windows.Forms.SaveFileDialog saveDlg = new System.Windows.Forms.SaveFileDialog();
string mydocPath = System.Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
saveDlg.InitialDirectory = mydocPath/* + "\\"*/;
saveDlg.Filter = "Bitmap(*.bmp)|*.bmp|JPEG(*.jpg)|*.jpg";
saveDlg.FilterIndex = 2;
saveDlg.FileName = "SView截图";
if (saveDlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
switch (saveDlg.FilterIndex)
{
case 1:
m_bmpLayerCurrent.Clone(new System.Drawing.Rectangle(0, 0, m_bmpLayerCurrent.Width, m_bmpLayerCurrent.Height),
System.Drawing.Imaging.PixelFormat.Format24bppRgb).Save(saveDlg.FileName,
System.Drawing.Imaging.ImageFormat.Bmp);
break;
case 2:
m_bmpLayerCurrent.Save(saveDlg.FileName,
System.Drawing.Imaging.ImageFormat.Jpeg);
break;
}
}
}
internal System.Drawing.Bitmap CopyBitmapFromScreenSnapshot(Rect region)
{
if(region.Width.Equals(0.0) || region.Height.Equals(0.0))
{
return null;
}
var sourceRect = region.ToRectangle();
var destRect = new Rectangle(0, 0, sourceRect.Width, sourceRect.Height);
if (screenSnapshot != null)
{
var bitmap = new Bitmap(sourceRect.Width, sourceRect.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using (Graphics g = Graphics.FromImage(bitmap))
{
g.DrawImage(screenSnapshot, destRect, sourceRect, GraphicsUnit.Pixel);
}
return bitmap;
}
return null;
}
public void Show(int timeOutSecond, System.Windows.Size? defaultSize)
{
if (timeOutSecond > 0)
{
if (timeOutTimmer == null)
{
timeOutTimmer = new Timer();
timeOutTimmer.Tick += OnTimeOutTimmerTick;
}
timeOutTimmer.Interval = timeOutSecond*1000;
timeOutTimmer.Start();
}
if(innerCanvas != null)
{
innerCanvas.DefaultSize = defaultSize;
}
Show();
Focus();
}
private void OnTimeOutTimmerTick(object sender, System.EventArgs e)
{
timeOutTimmer.Stop();
CancelCaputre();
}
public void DrawShowSize(Rect rec)
{
if(rec == Rect.Empty)
{
return;
}
var wX = rec.Width;
var hY = rec.Height;
label.Content = "选中区域大小:" + wX + "×" + hY + "宽:" + wX + "高:" + hY;
}
public void OKAction()
{
innerCanvas.finishAction();
}
public void CancelAction()
{
CancelCaputre();
}
protected override void OnMouseRightButtonUp(MouseButtonEventArgs e)
{
base.OnMouseRightButtonUp(e);
label.Visibility = Visibility.Hidden;
toolBarContrl.Visibility = Visibility.Hidden;
}
}
}
3 自定义toolbar
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace RisCaptureLib
{
/// <summary>
/// ToolBarControl.xaml 的交互逻辑
/// </summary>
public partial class ToolBarControl : UserControl
{
//确定事件
public delegate void OKEventHander();
public event OKEventHander OnOK;
//取消事件
public delegate void CancelEventHander();
public event CancelEventHander OnCancel;
//保存事件
public delegate void SaveCaptureEventHander();
public event SaveCaptureEventHander OnSaveCapture;
public ToolBarControl()
{
InitializeComponent();
}
private void buttonSave_Click(object sender, RoutedEventArgs e)
{
if (OnSaveCapture!=null)
{
OnSaveCapture();
}
buttonComplete_Click(sender, e);
}
private void buttonCancel_Click(object sender, RoutedEventArgs e)
{
if (OnCancel != null)
{
OnCancel();
}
}
private void buttonComplete_Click(object sender, RoutedEventArgs e)
{
if (OnOK != null)
{
OnOK();
}
}
}
}