前言 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截圖一樣的效果!