前言  QQ、微信截图功能已很强大了,似乎没必要在开发一个截图程序了。但是有时QQ热键就是被占用,不能快速的开启截屏;有时,天天挂着QQ,领导也不乐意。既然是程序员,就要自己开发截屏工具,功能随心所欲,岂不快哉。

再强调一点:工具就是生产力!没有掌握WPF之前,我是不会开发这么一个程序的,如果采用MFC、winform框架,工作量是相当的大,开发出来的效果肯定也比较low。本人用WPF,花了一天多的功夫,开发了这个小程序。程序的定位就功能简单,平时工作不碍事,用着的时候,一键截图!

 界面  执行程序下载地址:一键截图,点我下载。

为了不影响视觉, 程序主界面非常小。程序会在所有界面最前端展示。

有两个按钮1)“快捷截图”:截图后,立即将截图复制到剪切板。2)“截图+编辑”:截图后,可以在图上标注箭头和文字。

程序展开时,效果:

截图后,可编辑:

新增保留历史记录功能,选中历史记录,复制到剪切板。

截图类型:
静态:截取按下按钮那一刻的屏幕图片,图片是静止的(比如 截取视频,视频内容是静止的)。
动态:截屏内容是动态的,如果桌面有视频,是可以看到视频播放内容的。

看似简单,对开发技巧要求很高。内行看门道!

开发思路

  常言道:看到的不一定是真实的。开发也要这样。程序叫截屏,你不要一股劲想着怎么截取别的窗口图案,肯定很费劲!思虑就是掩人耳目:先将整个屏幕复制,放到自己程序窗体中,窗体最大化,覆盖整个屏幕!用户看到还是整个屏幕,但是整个屏幕已被偷梁换柱!此后,你所有的操作都是在自己窗体上处理,当然可以随心所欲了!

截取整个屏幕

       public Bitmap GetScreenSnapshot()
        {
            System.Drawing.Rectangle rc = SystemInformation.VirtualScreen;
            var bitmap = new Bitmap(rc.Width, rc.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            using (Graphics memoryGrahics = Graphics.FromImage(bitmap))
            {
                memoryGrahics.CopyFromScreen(rc.X, rc.Y, 0, 0, rc.Size, CopyPixelOperation.SourceCopy);
            }

            return bitmap;
        }

创建全屏窗体

注意窗体属性,这样才能全面覆盖整个屏幕。

图层布局

这个很有技巧!为了实现非截图区域阴影效果,费了一番心机!即使这样,感觉也比winform用起来得心应手!

注:我不是一直贬低winform,但是要承认,这两个东西不是一个时代产物。wpf设计思路比winform先进很多。只是wpf新概念多,用的人少,开发起来常常蒙圈!经过一段迷茫期,前途就会光明了!

窗口的布局,不多说了!直接上代码。我对代码做了注释!

<Window.Resources>
        <ControlTemplate x:Key="templatePushButton" TargetType="RadioButton">
            <Border x:Name="Part_Border" BorderThickness="1" BorderBrush="Gray"
                                        Background="{TemplateBinding Background}"
                                        Margin="{TemplateBinding Margin}"
                                        Padding="{TemplateBinding Padding}">
                <ContentPresenter></ContentPresenter>
            </Border>

            <ControlTemplate.Triggers >
                <Trigger Property="IsChecked" Value="True">
                    <Setter  TargetName="Part_Border"  Property="BorderBrush" Value="Blue"></Setter>
                </Trigger>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter  TargetName="Part_Border"  Property="Background" Value="#FFb2dff9"></Setter>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>

        <Style x:Key="stylePushButton" TargetType="RadioButton">
            <Setter Property="VerticalAlignment" Value="Center"></Setter>
            <Setter Property="Padding" Value="8,5,8,5"></Setter>
            <Setter Property="Template" Value="{StaticResource templatePushButton}"></Setter>
        </Style>

    </Window.Resources>
    <Grid Background="Green" >
        <!-- 整个屏幕图像 -->
        <Image x:Name="imgScreen"
               MouseDown="ImgScreen_MouseDown"
               MouseUp="ImgScreen_MouseUp"
               Stretch="None"
               MouseMove="ImgScreen_MouseMove">
        </Image>

        <!-- 覆盖一层黑色,半透明状 -->
        <Grid x:Name="gridCover" Visibility="Collapsed" Background="Black" Opacity="0.5">
        </Grid>

        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*"></RowDefinition>
                <RowDefinition Height="auto"></RowDefinition>
            </Grid.RowDefinitions>
            <!-- 前面覆盖了一层黑色,但是截取的图像不能覆盖,只能在这里再显示截取图像 -->
            <Grid x:Name="gridCutImg"
                  MouseDown="ImgCut_MouseDown"
                  MouseMove="ImgCut_MouseMove"
                   MouseUp="ImgCut_MouseUp">
                <Image x:Name="imgCut" Grid.RowSpan="3" Stretch="None"
                   HorizontalAlignment="Left" VerticalAlignment="Top"></Image>
                <!--用来画箭头和文字-->
                <Canvas x:Name="canvasEdit"  HorizontalAlignment='Left'
                        VerticalAlignment="Top"  Background="Transparent">

                </Canvas>
            </Grid>

            <!--显示提示信息-->
            <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"
                           FontSize="22" Foreground="Yellow"
                          Opacity="0.8" >滑动鼠标开始截屏 截图保存到剪切板 按ESC键退出</TextBlock>

            <StackPanel  Grid.RowSpan="3">
                <Grid >
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="auto"></ColumnDefinition>
                        <ColumnDefinition Width="*"></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                </Grid>
                <!--截图指示框-->
                <Border x:Name="borderSelect"
                HorizontalAlignment="Left" VerticalAlignment="Top"
                BorderThickness="1" BorderBrush="Red"></Border>
                <!--宽和高指示-->
                <Grid  HorizontalAlignment="Stretch" >
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="auto"></ColumnDefinition>
                        <ColumnDefinition Width="auto"></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                    <TextBlock x:Name="txtCutInfo"  Padding="8,5,8,5"
                               HorizontalAlignment="Left"
                              Background="White" VerticalAlignment="Center">1</TextBlock>
                    <StackPanel x:Name="stackEdit" Orientation="Horizontal" HorizontalAlignment="Right" Grid.Column="1" Margin="2">
                        <RadioButton x:Name="radioArrow" GroupName="editType" Click="RadioArrow_Click" Foreground="Black" Padding="10,5,10,5" Style="{StaticResource stylePushButton}">↑</RadioButton>
                        <RadioButton  x:Name="radioText"  GroupName="editType" Click="RadioText_Click" Foreground="Black" Style="{StaticResource stylePushButton}">文</RadioButton>
                        <RadioButton  x:Name="radioClose" Click="RadioClose_Click" Foreground="Red" Style="{StaticResource stylePushButton}">X</RadioButton>
                    </StackPanel>
                </Grid>

            </StackPanel>

        </Grid>
    </Grid>

当鼠标移动时,不断的计算选中区域,设置borderSelect属性。

 private void ImgScreen_MouseMove(object sender, MouseEventArgs e)
        {
            if (!_isMouseDown)
                return;

            gridCover.Visibility = Visibility.Visible;

            //计算鼠标选中区域
            Point currentPoint = e.GetPosition(imgScreen);
            Point borderPoint = e.GetPosition(borderSelect);

            double xDelta = xDelta_BoderToImgScreen;
            double yDelta = yDelta_BoderToImgScreen;

            _rectImgCut = ImageHelper.ToRect(currentPoint, _startPoint);

            Rect rectBoderCut = ImageHelper.ToRect(new Point(currentPoint.X + xDelta, currentPoint.Y + yDelta),
                new Point(_startPoint.X + xDelta, _startPoint.Y + yDelta));

            //设置方框位置和大小
            Thickness thickness = new Thickness(rectBoderCut.Left, rectBoderCut.Top, 0, 0);
            borderSelect.SetValue(FrameworkElement.MarginProperty, thickness);
            imgCut.SetValue(FrameworkElement.MarginProperty, thickness);

            thickness = new Thickness(rectBoderCut.Left, 3, 0, 0);
            txtCutInfo.SetValue(FrameworkElement.MarginProperty, thickness);

            borderSelect.Width = Math.Abs(_startPoint.X - currentPoint.X);
            borderSelect.Height = Math.Abs(_startPoint.Y - currentPoint.Y);
            borderSelect.Visibility = Visibility.Visible;

            //为了防止整个图 变暗,鼠标选中区域图像抠图,再在上层图像上显示
            imgCut.Source = GetBitmapCut();

            Int32Rect imgDestRect = GetCutRect();
            txtCutInfo.Text = string.Format($"宽:{imgDestRect.Width} 高:{imgDestRect.Height}");
        }

到此,程序主要逻辑处理完毕!麻雀虽小五脏俱全!这里用到不少wpf布局技巧。这些技巧与winform处理思虑差别还是很大的!wpf虽然苦涩难懂,感觉一入候门深似海!如果坚持下来,就会感到豁然开朗,也理解了微软的一片苦心!

程序运行效果与QQ截图很类似了。顺着这个思虑往前走,完全可以开发出与QQ截图一样的效果!

采用WPF技术开发截图程序的更多相关文章

  1. 采用WPF开发截图程序,so easy!

    前言  QQ.微信截图功能已很强大了,似乎没必要在开发一个截图程序了.但是有时QQ热键就是被占用,不能快速的开启截屏:有时,天天挂着QQ,领导也不乐意.既然是程序员,就要自己开发截屏工具,功能随心所欲 ...

  2. 采用WPF技术,开发OFD电子文档阅读器

    前言 OFD是国家标准版式文档格式,于2016年生效.OFD文档国家标准参见<电子文件存储与交换格式版式文档>.既然是国家标准,OFD随后肯定会首先在政务系统使用,并逐步推向社会各个方面. ...

  3. 采用QT技术,开发OFD电子文档阅读器

    前言 ofd作为板式文档规范,相当于国产化的pdf.由于pdf标准制定的较早,相关生态也比较完备,市面上的pdf阅读器种类繁多.国内ofd阅读器寥寥无几,作者此前采用wpf开发了一款阅读器,但该阅读器 ...

  4. Java技术开发程序员如果在2019年立足

    2019年的互联网环境相对以往来说要更复杂一些,互联网领域也正在经历从消费互联网向产业互联网转型的阵痛期.其实不少公司从2018年开始已经在陆续进行结构化调整,这些调整中的重要内容就是岗位调整,而岗位 ...

  5. WCF/WPF公司内部订餐程序开发

    WCF/WPF公司内部订餐程序开发 (服务端篇) 上班的第一天,群里讨论关于订餐的问题,所以想到了要不要自己开发一个公司内部的订餐系统呢?方便公司内部员工的订餐,有了想法就简单的实践了下 . 实现还是 ...

  6. 从程序员小仙飞升上神,java技术开发要如何实现?

    新霸哥是一个专业从事java开发的,近期,新霸哥发现很多的朋友在问,从程序员小仙飞升上神难吗?在此新霸哥将为你详细的介绍,下面新霸哥将从新手入门和老司机进阶多方面详细的为大家介绍一下. 说起java首 ...

  7. WPF学习开发客户端软件-任务助手(下 2015年2月4日代码更新)

    时光如梭,距离第一次写的 WPF学习开发客户端软件-任务助手(已上传源码)  已有三个多月,期间我断断续续地对该项目做了优化.完善等等工作,现在重新向大家介绍一下,希望各位可以使用,本软件以实用性为主 ...

  8. 跟我一起学WCF(2)——利用.NET Remoting技术开发分布式应用

    一.引言 上一篇博文分享了消息队列(MSMQ)技术来实现分布式应用,在这篇博文继续分享下.NET平台下另一种分布式技术——.NET Remoting. 二..NET Remoting 介绍 2.1 . ...

  9. NS实现采用的技术大多是PHP,如果采用java、 .net是否同样适用?

    SNS采用的技术可不都是PHP (不局限于国内),特别是国外的新兴公司,基本上没有再用PHP的了,国内到还是蛮常用的.简单说说我知道的几个案例:Facebook (PHP):Facebook采用PHP ...

随机推荐

  1. Django学习系列13:Django ORM和第一个模型

    ORM—对象关系映射器,是一个数据抽象层,描述存储在数据库中的表,行和列.处理数据库时,可以使用熟悉的面向对象方式,写出更好的代码. 在ORM的概念中,类对应数据库中的表,属性对应列,类的单个实例表示 ...

  2. 简单了解Oracle的回滚段

    因为上一次研究了Oracle的事务一致性,中间查阅资料的时候,看到这个地方与回滚段有关.所以就罗列了以下简单的知识.更为深层次的就不再深挖了,个人感觉对于事务的一致性和隔离级别是开发经理应该了解的,但 ...

  3. hiho #1502:最大子矩阵(元素和不超过k)

    #1502 : 最大子矩阵 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个NxM的矩阵A和一个整数K,小Hi希望你能求出其中最大(元素数目最多)的子矩阵,并且该 ...

  4. 16.html转pdf的一个小示例

    def get_html(request): data = {"name": "alex", "age": 12, "sex&qu ...

  5. Window 环境升级node版本

    https://github.com/Kenshin/gnvm 下载gnvm,安装在node文件目录下 gnvm version 然后打开cmd命令行窗口,输入:gnvm update latest, ...

  6. IE浏览器如何实现断点续传

    需求: 支持大文件批量上传(20G)和下载,同时需要保证上传期间用户电脑不出现卡死等体验: 内网百兆网络上传速度为12MB/S 服务器内存占用低 支持文件夹上传,文件夹中的文件数量达到1万个以上,且包 ...

  7. BZOJ 2905: 背单词 AC自动机+fail树+dfs序+线段树

    Description 给定一张包含N个单词的表,每个单词有个价值W.要求从中选出一个子序列使得其中的每个单词是后一个单词的子串,最大化子序列中W的和. Input 第一行一个整数TEST,表示数据组 ...

  8. CSP2019-S2参赛总结 暨 近期学习反思

    前言 岁月不居,时节如流.眨眼间,2019的联赛就已经落下帷幕了,回忆这一年的学习,有许许多多的事情想写下来.趁联赛结果还未出来,赶紧写下这篇文章,以记录我这段时间的学习和生活. "你怎么又 ...

  9. 微信小程序_(视图)简单的scroll-view容器

    scroll-view容器效果 官方文档:传送门 scroll-view 可滚动视图区域 scroll-x Boolean false 允许横向滚动 scroll-y Boolean false 允许 ...

  10. linux 下使用命令查看jvm信息

    java程序员除了编写业务代码之外,特别是项目上线之后,更需要关注的是系统的性能表现,这个时候就需要了解一下jvm的性能表现了,可以借助于java虚拟机自带的一些分析工具,主要有三个常用的命令. 1. ...