zoukankan      html  css  js  c++  java
  • C#中实现QQ截图的功能及相关问题

    对于QQ截图,肯定是早就有认识了,只是一直没有去认真观察这个操作的具体实现步骤。所以这里将自己的记忆中的步骤简单的写一下:

    习惯性用QQ或者TIM的人,一般是使用Ctrl+Alt+A  快捷键(热键)快速实现截图。

    1. Ctrl+Alt+A  进入截图模式
    2. 鼠标左键点击
    3. 鼠标拖动对截图去进行选取
    4. 鼠标左键弹起
    5. 双击截图区域  保存图片到剪贴板
    6. 鼠标右键点击
    7. 退出截图模式

    因为考虑到截图模式的时候  一般只能显示一个窗体  所以就考虑使用单例模式  在ScreenBody窗体中实现以下代码

    1:创建单例  

    private static ScreenBody screenBody=null;

    2:私有化构造函数

    private ScreenBody()
    {
    InitializeComponent();
    }

    3:创建静态方法

    private static ScreenBody GetSingle()
    {
    if(screenBody==null)
    {
    screenBody=new ScreenBody();
    }
    return screenBody;
    }

    进一步讨论一下在Main窗体中的调用  Main中添加了一个button 命名为btnCutter  

    private void btnCutter_Click(object sender,EventArgs e)
    {
     //新建一个和屏幕大小相同的图片img  也可以用BitMap
    image img=new Bitmap(Screen.AllScreens[0].Bounds.Width,Screen.AllScreens[0].Bounds.Height);
    //创建一个画板 让我们可以在画板上画图  大小和屏幕大小一样大
    Graphics g=Graphics.FromImage(img);
     //将屏幕图片拷贝到空白图片img
    g.CopyFromScreen(new Point(0,0),new Point(0,0),Screen.AllScreens[0].Bounds.Size);
    //创建截图窗体
    ScreenBody body=ScreenBody.GetSingle();
    //指示窗体的背景图片为屏幕图片
    body.BackGroundImage=img;
    body.ShowDialog();
    
    }

     对于窗体ScreenBody

    声明全局变量

            private bool CatchStart;//判断鼠标是否按下
            private bool CatchFinished;//判断矩形是否绘制完成
            private Point DownPoint;//鼠标按下的点
            private Image baseMap;//最基本的图片
            private Rectangle CatchRectangle;    

      必须要实现的那几个事件

    • 鼠标按下MouseDown
    •  private void ScreenBody_MouseDown(object sender, MouseEventArgs e)
              {
                  //鼠标左键按下就是开始画图,也就是截图
                  if (e.Button == MouseButtons.Left)
                  {
                      if (CatchStart == false)
                      {
                          CatchStart = true;
                          //保存此时的坐标
                          DownPoint = new Point(e.X, e.Y);
                      }
                  }
              }

      鼠标移动 MouseMove

    •  private void ScreenBody_MouseMove(object sender, MouseEventArgs e)
              {
                  //确保截图开始
                  if (CatchStart)
                  {
                      //新建一个图片,让它与屏幕图片相同
                      Bitmap copyBmp = (Bitmap)baseMap.Clone();
                      //鼠标按下时的坐标
                      Point newPoint = new Point(DownPoint.X, DownPoint.Y);
      
                      //新建画板和画笔
                      Graphics g = Graphics.FromImage(copyBmp);
                      Pen p = new Pen(Color.Azure, 1);//画笔的颜色为azure 宽度为1
      
                      //获取矩形的长度 
                      int width = Math.Abs(e.X - DownPoint.Y);
                      int height = Math.Abs(e.Y - DownPoint.Y);
      
                      if (e.X < DownPoint.X)
                      {
                          newPoint.X = e.X;
      
                      }
                      if (e.Y < DownPoint.Y)
                      {
                          newPoint.Y = e.Y;
                      }
      
                      CatchRectangle = new Rectangle(newPoint, new Size(width, height));
                      g.DrawRectangle(p, CatchRectangle);
      
                      //释放目前的画板
                      g.Dispose();
                      p.Dispose();
      
                      //从当前窗体创建新的画板
                      Graphics g1 = this.CreateGraphics();
                      //将刚刚所画的图片画到截图窗体上去
                      //为什么不直接在当前窗体画图呢???
                      //如果直接解决将矩形画在窗体上,会造成图片抖动而且有多个矩形
                      //这样实现也属于二次缓冲技术
                      g1.DrawImage(copyBmp, new Point(0, 0));
                      g1.Dispose();
      
                      //释放拷贝图片 防止内存被大量的消耗
                      copyBmp.Dispose();
                  }

      鼠标弹起 Mouseup

    •   /// <summary>
              /// 鼠标左键弹起事件
              /// </summary>
              /// <param name="sender"></param>
              /// <param name="e"></param>
              private void ScreenBody_MouseUp(object sender, MouseEventArgs e)
              {
                  if (e.Button == MouseButtons.Left)
                  {
                      //如果截图已经开始,鼠标左键弹起设置截图完成
                      if (CatchStart)
                      {
                          CatchStart = false;
                          CatchFinished = true;
                      }
                  }
              }

      鼠标双击

    •  private void ScreenBody_MouseDoubleClick(object sender, MouseEventArgs e)
              {
                  if (e.Button==MouseButtons.Left&&CatchFinished)
                  {
                      //新建一个矩形大小相同的空白图片
                      Bitmap CatcheBmp = new Bitmap(CatchRectangle.Width, CatchRectangle.Height);
                      Graphics g = Graphics.FromImage(CatcheBmp); ;
                 
                      //把basemap中指定的部分按照指定大小画到空白图片上
                      //CatchRectangle指定的baseMap中指定的部分
                      //第二个参数指定绘制到空白图片的位置和大小
                      //画完后CatchedBmp不再是空白图片,而是具有与截取的图片一样的内容
                      g.DrawImage(baseMap, new Rectangle(0, 0, CatchRectangle.Width, CatchRectangle.Height));
      
                      //将图片保存到剪切板中
                      Clipboard.SetImage(CatcheBmp);
                      g.Dispose();
      
                      CatchFinished = false;
                      this.BackgroundImage = baseMap;
                      CatcheBmp.Dispose();
                      this.DialogResult = DialogResult.OK;
                      this.Close();
                  }
              }

      鼠标右键 退出截图

    •  /// <summary>
              /// 鼠标右键点击结束截图
              /// </summary>
              /// <param name="sender"></param>
              /// <param name="e"></param>
              private void ScreenBody_MouseClick(object sender, MouseEventArgs e)
              {
                  if (e.Button == MouseButtons.Right)
                  {
                      this.DialogResult = DialogResult.OK;
                      this.Close();
                  }
              }

      最复杂的热键注册  自己也是去网上看的  Main窗体中

    • 声明枚举
       [FlagsAttribute]
          public enum KeyModifiers
          {
              None = 0,
              Alt = 1,
              Ctrl = 2,
              Shift = 4,
              WindowsKey = 8
          }
      

        然后在类中编辑一下代码

    •  //在C#中引用命名空间System.Runtime.InteropServices;来加载非托管类user32.dll
              /*
              * RegisterHotKey函数原型及说明:
              * BOOL RegisterHotKey(
              * HWND hWnd,         // window to receive hot-key notification
              * int id,            // identifier of hot key
              * UINT fsModifiers, // key-modifier flags
              * UINT vk            // virtual-key code);
              * 参数 id为你自己定义的一个ID值
              * 对一个线程来讲其值必需在0x0000 - 0xBFFF范围之内,十进制为0~49151
              * 对DLL来讲其值必需在0xC000 - 0xFFFF 范围之内,十进制为49152~65535
              * 在同一进程内该值必须唯一参数 fsModifiers指明与热键联合使用按键
              * 可取值为:MOD_ALT MOD_CONTROL MOD_WIN MOD_SHIFT参数,或数字0为无,1为Alt,2为Control,4为Shift,8为Windows
              * vk指明热键的虚拟键码
              */
              [System.Runtime.InteropServices.DllImport("user32.dll")] //申明API函数
              public static extern bool RegisterHotKey(
               IntPtr hWnd, // handle to window
               int id, // hot key identifier
               uint fsModifiers, // key-modifier options
               Keys vk // virtual-key code
              );
      
              [System.Runtime.InteropServices.DllImport("user32.dll")] //申明API函数
              public static extern bool UnregisterHotKey(
               IntPtr hWnd, // handle to window
               int id // hot key identifier
              );

      再接着

       private void Form1_Load(object sender, EventArgs e)
              {
                  uint ctrlHotKey = (uint)(KeyModifiers.Alt | KeyModifiers.Ctrl);
                  // 注册热键为Alt+Ctrl+C, "100"为唯一标识热键
                  RegisterHotKey(Handle, 100, ctrlHotKey, Keys.A);
              }
              //热键按下执行的方法
              private void GlobalKeyProcess()
              {
                  this.WindowState = FormWindowState.Minimized;
                  //窗口最小化需要一定的时间  使用线程
                  Thread.Sleep(200);
                  btnCutter.PerformClick();
              }
      
              protected override void WndProc(ref Message m)
              {
                  //如果m.Msg的值为0x0312那么表示用户按下了热键
                  const int WM_HOTKEY = 0x0312;
                  switch (m.Msg)
                  {
                      case WM_HOTKEY:
                          if (m.WParam.ToString()=="100")
                          {
                              GlobalKeyProcess();
                          }
                          break;
                      default:
                          break;
                  }
                  base.WndProc(ref m);
              }
      
              private void Form1_FormClosing(object sender, FormClosingEventArgs e)
              {
                  // 卸载热键
                  UnregisterHotKey(Handle, 100);
              }

      热键的功能就能实现。但是我遇到了很多问题  首先是basemap  没有初始化值

    • 这些问题  还有待解决!!!
  • 相关阅读:
    php7垃圾回收机制
    PHP-FPM
    go main.main之前的准备
    ElementUI MessageBox 弹框
    ElementUI table 样式修改
    ElementUI Dropdown 下拉菜单
    vue+django实现下载文件
    ElementUI 点击展开/隐藏
    vue+django实现websocket连接
    ElementUI 上传文件以及限制
  • 原文地址:https://www.cnblogs.com/Audient/p/7684922.html
Copyright © 2011-2022 走看看