• 采用WPF技术开发截图程序 (可下载)


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

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

     界面  执行程序下载地址: 一键截图,点我下载。  获取最新版本和其他相关工具,可加入QQ群:920519255;

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

    有两个按钮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截图一样的效果!

  • 相关阅读:
    一些前端面试题
    CSS高度塌陷问题解决方案
    闭包
    作用域
    JS的预编译过程
    小技巧集合
    序选择器
    HTML初始结构
    剖析Vue原理&实现双向绑定MVVM
    Safari 3D transform变换z-index层级渲染异常
  • 原文地址:https://www.cnblogs.com/yuanchenhui/p/screenshot-easy.html
Copyright © 2020-2023  润新知