博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一个截屏工具制作的全过程记录——如何使用“拿来主义”
阅读量:5061 次
发布时间:2019-06-12

本文共 6533 字,大约阅读时间需要 21 分钟。

第一部分,截屏功能的实现

利用关键字“.netcapture speicified area”在Google中搜索现成的答案,从答案中,我直接进行“相面”,打开看起来比较满足条件的第二和第三条记录。

逐个打开搜索结果看一看,比较符合我的要求的是“http://stackoverflow.com/questions/3306600/c-how-to-take-a-screenshot-of-a-portion-of-screen”,代码如下:

 

Rectangle rect= new Rectangle(0, 0, 100, 100);Bitmap bmp =new Bitmap(rect.Width, rect.Height, PixelFormat.Format32bppArgb);Graphics g =Graphics.FromImage(bmp);g.CopyFromScreen(rect.Left,rect.Top, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy);bmp.Save(fileName,ImageFormat.Jpeg);

这份代码的作用就是自定义一个处于屏幕内的一块矩形区域,然后截取矩形区域内的屏幕图像。

 

第二部分,矩形工具的实现

Google关键字“C#how to resize a none border form”,第一条就是答案!

代码如下:

 

public partial class Form1 : Form {    public Form1() {      InitializeComponent();      this.FormBorderStyle = FormBorderStyle.None;      this.DoubleBuffered = true;      this.SetStyle(ControlStyles.ResizeRedraw, true);    }    private const int cGrip = 16;      // Grip size    private const int cCaption = 25;   // Caption bar height;    protected override void OnPaint(PaintEventArgs e) {      Rectangle rc = new Rectangle(this.ClientSize.Width - cGrip, this.ClientSize.Height - cGrip, cGrip, cGrip);      ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, rc);      rc = new Rectangle(0, 0, this.ClientSize.Width, 32);      e.Graphics.FillRectangle(Brushes.DarkBlue, rc);    }     protected override void WndProc(ref Message m) {      if (m.Msg == 0x84) {  // Trap WM_NCHITTEST        Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);        pos = this.PointToClient(pos);        if (pos.Y < cCaption) {          m.Result = (IntPtr)2;  // HTCAPTION          return;        }        if (pos.X >= this.ClientSize.Width - cGrip && pos.Y >= this.ClientSize.Height - cGrip) {          m.Result = (IntPtr)17; // HTBOTTOMRIGHT          return;        }      }      base.WndProc(ref m);    }  }

 

上段代码实现了一个可拖拽、可调节大小的无边框样式的窗体。重点内容有两处,一个是标题栏的自绘,另一个是对用户交互区域的绘制。因为截图工具并不需要标题栏,所以完全可以把下面的代码删除,这样自绘的标题栏就不会显示。

rc = new Rectangle(0, 0, this.ClientSize.Width, 32);      e.Graphics.FillRectangle(Brushes.DarkBlue, rc);

虽然自绘标题栏消失了,但WndProc还是会检测用户压下鼠标动作,并把客户区坐标小于cCaption的动作当作压下标题栏来处理。而我真正需要的是拖拽整个窗体,而非只是针对标题栏,所以需要把pos.Y < cCaption的限定范围扩大,所以修改后的代码应该如下:

if (pos.X >= this.ClientSize.Width - cGrip && pos.Y >= this.ClientSize.Height - cGrip)        {          m.Result = (IntPtr)17; // HTBOTTOMRIGHT          return;        } else {          m.Result = (IntPtr)2;  // HTCAPTION          return;        }

先处理右下角与用户交互的可调整窗体大小的提示区域,然后把非客户区的其它消息当作标题栏交互消息处理,这样就可以实现窗体拖拽的效果了。

对于窗体大小调整的功能,程序中分两步实现:第一步是在protected override void OnPaint(PaintEventArgs e)中绘制了一个交互性图标,用户通过它可以对窗体的大小进行调节;第二步则是将非客户区,且鼠标处于指定范围内的消息,当作HTBOTTOMRIGHT处理,即右下角的调节大小(当然,也可以为八个方向编写对应的处理,其它的可用值见http://msdn.microsoft.com/en-us/library/windows/desktop/ms645618%28v=vs.85%29.aspx)。

现在已经完美地解决了拖拽,在测试阶段却发现标题栏特有的附加功能——双击。怎么屏蔽呢?从代码中可用看出,我们一直都在处理WM_NCHITTEST消息,其余的消息都用默认的base.WndProc处理了。为了能够达到屏蔽的效果,可用添加一个双击消息的处理,即不做任何处理

if(m.Msg == 0xA3)       // WM_NCLBUTTONDBLCLK      {        m.Result = IntPtr.Zero;                           return;      }

第三部分:如何设置半透明效果:

Google关键字“c#transparent form”,第一条为答案!

BackColor = Color.Lime;TransparencyKey = Color.Lime;

运行一下看效果,且慢!不对啊,画面上什么都没有了,完全看不到窗体!回想了一下,TransparencyKey会将画面中指定的颜色部分搞成全透明的,所以就什么都看不见了。这时又想到了Opacity,OK,搞定!

关于透明,这里要多提一句,TransparencyKey和Opacity,前者功能是让指定颜色完全透明,后者则是让窗体半透明,在后面完整的源码中,我会给出相应的代码例子。

 

第四部分,全局热键

Google关键字“c#global shortcut key for my exe”,这个稍微复杂了些,从答案中并没有直接给出代码,但从推荐的网站“http://www.dreamincode.net/forums/topic/180436-global-hotkeys/”中我们可以找到现成代码可以下载。但是公司的Policy比较严,不能随便下,所以放弃。

 

 

换个关键字“c#global shortcut key example”,第一个就是答案:http://stackoverflow.com/questions/3654787/global-hotkey-in-console-application,代码也有贴出,内容有点长,请参考后面的完整源码部分。

第五部分,图像保存

有了上面的调查结果,我们差不多已经调查完80%的功能了,剩下的基本上就是一些使用上的功能,在这个截图工具中,我打算采用两种保存图片的功能:一个是直接保存到内存中,这样方便直接粘贴到Word这样的高级编辑器中,还有一种就是弹出SaveDialog对话框,让用户自行选择保存地址,生成物理文件。使用关键字“c# copybitmap to clipboard”可以很容易地找到第一种方法的答案,而关于第二种这里就不多做解释了,“http://msdn.microsoft.com/en-us/library/sfezx97z.aspx”里有完整的答案。

下面是把截图保存到内存的实现代码,关键内容就是Clipboard.SetImage:

 

private void button1_Click(object sender, EventArgs e)        {            Rectangle r = this.RectangleToScreen(ClientRectangle);            Bitmap b = GetDesktopImage(r);            Clipboard.SetImage(b);        }         public Bitmap GetDesktopImage(Rectangle rect)        {            Graphics graphics;            Bitmap bitmap;            bitmap = new Bitmap(rect.Width, rect.Height);            graphics = Graphics.FromImage(bitmap);            graphics.CopyFromScreen(rect.Left, rect.Top, 0, 0, new Size(rect.Width, rect.Height));            return bitmap;        }

 

文件保存成物理文件可以参考“http://stackoverflow.com/questions/457370/c-how-to-convert-bitmap-byte-array-to-jpeg-format”,代码如下:

using(Image img = Image.FromFile("foo.bmp"))    {        img.Save("foo.jpg", ImageFormat.Jpeg);    }

注意,在调用文件保存到内存时,代码会执行出错,原因可能是OLE对象的问题。通过“http://stackoverflow.com/questions/798464/how-to-invoke-with-action”的答案可以找到解决方案。

参考方案

解决方案

地址

跨线程访问控件

全局快捷键

SaveDialog用法

禁用双击

保存屏幕截图到内存

保存图片到磁盘

按键参考大全

非客户区WM_NCHITTEST消息参考

禁止关闭

C# prevent closing

隐藏与显示

Form.Visible = !Form.Visible

系统托盘

C# system tray

http://alanbondo.wordpress.com/2008/06/22/creating-a-system-tray-app-with-c/

public interface SystemTrayHandler    {        void OnSystemTrayShow(object sender, EventArgs e);        void OnSystemTrayExit(object sender, EventArgs e);    }    public class SystemTrayLoader    {        public static void WrapFormWithSysTray(SystemTrayHandler handler)        {            // Create a simple tray menu with only one item.            ContextMenu trayMenu = new ContextMenu();            trayMenu.MenuItems.Add("Show Infected Area", handler.OnSystemTrayShow);            trayMenu.MenuItems.Add("Exit Shotit", handler.OnSystemTrayExit);             // Create a tray icon. In this example we use a            // standard system icon for simplicity, but you            // can of course use your own custom icon too.            NotifyIcon trayIcon = new NotifyIcon();            trayIcon.Text = "Shotit by wooooody```";            trayIcon.Icon = new Icon(SystemIcons.Application, 40, 40);             // Add menu to tray icon and show it.            trayIcon.ContextMenu = trayMenu;            trayIcon.Visible     = true;        }    }

双击系统托盘

http://www.developer.com/net/net/article.php/3336751/C-Tip-Placing-Your-C-Application-in-the-System-Tray.htm

C# double click system tray

内存中默认保存Png格式

http://stackoverflow.com/questions/3517965/convert-bmp-to-png-in-memory-for-clipboard-pasting-in-net

 

转载于:https://www.cnblogs.com/xinyuyuanm/archive/2013/04/17/3027061.html

你可能感兴趣的文章
控制文件的备份与恢复
查看>>
返回代码hdu 2054 A==B?
查看>>
PHP的SQL注入技术实现以及预防措施
查看>>
软件目录结构规范
查看>>
mysqladmin
查看>>
解决 No Entity Framework provider found for the ADO.NET provider
查看>>
设置虚拟机虚拟机中fedora上网配置-bridge连接方式(图解)
查看>>
HEVC播放器出炉,迅雷看看支持H.265
查看>>
[置顶] Android仿人人客户端(v5.7.1)——人人授权访问界面
查看>>
Eclipse 调试的时候Tomcat报错启动不了
查看>>
ES6内置方法find 和 filter的区别在哪
查看>>
Android入门之文件系统操作(二)文件操作相关指令
查看>>
Android实现 ScrollView + ListView无滚动条滚动
查看>>
java学习笔记之String类
查看>>
UVA 11082 Matrix Decompressing 矩阵解压(最大流,经典)
查看>>
jdk从1.8降到jdk1.7失败
查看>>
硬件笔记之Thinkpad T470P更换2K屏幕
查看>>
【知识库】-数据库_MySQL 的七种 join
查看>>
iOS开发——缩放图片
查看>>
HTTP之URL的快捷方式
查看>>