当前位置: 移动技术网 > IT编程>开发语言>.net > 截图小工具开发笔记

截图小工具开发笔记

2019年05月12日  | 移动技术网IT编程  | 我要评论

杰西卡-奥尔森,盈钻网贷,黄兴北路

一、开发环境及工具

windows 7 系统,开发软件为microsoft visual studio ultimate 2012

二、实现的功能

屏幕截屏,保存到图片或者保存到剪切板。截屏范围可以随意移动或者改变大小,自由度很高。先预览一下效果:

三、实现原理

2个窗体,1个是主窗体,主要功能进行热键设置,抓取屏幕到图片传给另一个窗体,另一个窗体对传过来的图片继续截取等操作。

四、开发手记

1.新建winform项目

2.主界面设计如图:

窗体主要属性设置如下:

//窗口样式
this.formborderstyle = system.windows.forms.formborderstyle.fixeddialog;
//窗口图标
  this.icon = ((system.drawing.icon)(resources.getobject("$this.icon")));
//禁止最大化            
this.maximizebox = false;
//窗口名称
 this.name = "piccut";
//窗口初始位置为屏幕中心
this.startposition = system.windows.forms.formstartposition.centerscreen;
//窗口标题为“截图设置”
this.text = "截图设置";
//窗口浮在所有窗口上面
 this.topmost = true;

 

 

此窗口内主要包括2label控件,1combobox1picturebox,摆放位置如上图。label用于显示文字说明;combobox用于显示热键09个数字供选择;picturebox用于显示二维码图片。

3.主界面的主要功能是对热键进行设置,同时我们程序运行,该界面自动最小化到托盘,双击进行截图,有机显示上述主界面进行设置,设置完毕可以最小化自动到托盘,点击关闭程序会自动退出。

 

1)自动到托盘

主界面拖入“notifyicon”,主要属性设置如下图,其中text是鼠标滑动到拖盘区域图标上的提示;icon是托盘图标;visible设置为false,默认不显示托盘区域图标。

 

 

主要程序代码。窗体载入时,最小化窗体,同时设置combobox空间的默认值。

private void piccut_load(object sender, eventargs e)
{
this.windowstate = formwindowstate.minimized; numbercbox.selectedindex = cutpicset.default.keynumber; }

 

窗口大小发生变化时,如果窗口最小化,隐藏当前窗体,托盘区域显示图标。

private void piccut_sizechanged(object sender, eventargs e)
 {
           if (this.windowstate == formwindowstate.minimized)
            {
                 this.hide();
                minnot.visible = true;   
            }
 }

 

上述两段代码实现了,程序开始运行时候,窗口最小化隐藏,同时托盘区域显示图标。

(2)托盘图标左键双击进行截图操作

private void minnot_mousedoubleclick(object sender, mouseeventargs e)
{
      if (e.button==mousebuttons.left)
     {
//显示截图窗体
showcutpic(); } }

 

showcutpic函数:
protected void showcutpic()
        {
            // 创建的空白图片和屏幕大小一样大的图片
            bitmap catchbmp = new bitmap(screen.allscreens[0].bounds.width, screen.allscreens[0].bounds.height);            
            // 我们可以通过graphics这个类在这个空白图片上画图
            graphics g = graphics.fromimage(catchbmp);
            // 把屏幕图片拷贝到我们创建的空白图片 catchbmp中
            g.copyfromscreen(new point(0, 0), new point(0, 0), new size(screen.allscreens[0].bounds.width, screen.allscreens[0].bounds.height));
            //这个我们截图的窗体创建截图窗体
            cutter = new cutpic();
             // 截图窗体的图片属性设置我们刚才新建的图片;
            cutter.image = catchbmp;
           //显示窗体
            cutter.showdialog();
        }

 

 

3)托盘图标右键单击显示界面设置

 private void minnot_mouseclick(object sender, mouseeventargs e)
        {
            if (e.button== mousebuttons.right)
            {
//显示主窗体
                this.show();
//隐藏托盘图标
                minnot.visible = false;
//当前窗口普通设置
                this.windowstate = formwindowstate.normal;               
            }
                   
        }

 

4)热键设置

/// <summary>
        /// 如果函数执行成功,返回值不为0。
        /// 如果函数执行失败,返回值为0。要得到扩展错误信息,调用getlasterror。
        /// </summary>
        /// <param name="hwnd">要定义热键的窗口的句柄</param>
        /// <param name="id">定义热键id(不能与其它id重复)</param>
        /// <param name="fsmodifiers">标识热键是否在按alt、ctrl、shift、windows等键时才会生效</param>
        /// <param name="vk">定义热键的内容</param>
        /// <returns></returns>
        [dllimport("user32.dll", setlasterror = true)]
        public static extern bool registerhotkey(intptr hwnd, int id, keymodifiers fsmodifiers, keys vk);

        /// <summary>
        /// 注销热键
        /// </summary>
        /// <param name="hwnd">要取消热键的窗口的句柄</param>
        /// <param name="id">要取消热键的id</param>
        /// <returns></returns>
        [dllimport("user32.dll", setlasterror = true)]
        public static extern bool unregisterhotkey(intptr hwnd, int id);

        /// <summary>
        /// 辅助键名称。
        /// alt, ctrl, shift, windowskey
        /// </summary>
        [flags()]
        public enum keymodifiers { none = 0, alt = 1, ctrl = 2, shift = 4, windowskey = 8 }

        /// <summary>
        /// 注册热键
        /// </summary>
        /// <param name="hwnd">窗口句柄</param>
        /// <param name="hotkey_id">热键id</param>
        /// <param name="keymodifiers">组合键</param>
        /// <param name="key">热键</param>
        public static void reghotkey(intptr hwnd, int hotkeyid, keymodifiers keymodifiers, keys key)
        {
            if (!registerhotkey(hwnd, hotkeyid, keymodifiers, key))
            {
                int errorcode = marshal.getlastwin32error();
                if (errorcode == 1409)
                {
                    messagebox.show("热键被占用 !");
                }
                else
                {
                    messagebox.show("注册热键失败!错误代码:" + errorcode);
                }
            }
        }

        /// <summary>
        /// 注销热键
        /// </summary>
        /// <param name="hwnd">窗口句柄</param>
        /// <param name="hotkey_id">热键id</param>
        public static void unreghotkey(intptr hwnd, int hotkeyid)
        {
            //注销指定的热键
            unregisterhotkey(hwnd, hotkeyid);
        }
private const int wm_hotkey = 0x312; //窗口消息-热键
        private const int wm_create = 0x1; //窗口消息-创建
        private const int wm_destroy = 0x2; //窗口消息-销毁
        private const int space = 0x3572; //热键id
        protected override void wndproc(ref message m)
        {
            base.wndproc(ref m);
            switch (m.msg)
            {
                case wm_hotkey: //窗口消息-热键id
                    switch (m.wparam.toint32())
                    {
                        case space: //热键id
//按下热键显示截图窗体
                            showcutpic();
                            break;
                        default:
                            break;
                    }
                    break;
                case wm_create: //窗口消息-创建
                    sethotkey(cutpicset.default.keynumber);
                    break;
                case wm_destroy: //窗口消息-销毁
                    unreghotkey(handle, space); //销毁热键
                    break;
                default:
                    break;
            }
        }

        public void sethotkey(int keynumber)
        {
            if (keynumber == 0)
            {
                reghotkey(handle, space, keymodifiers.ctrl, keys.d0);
            }
            else if (keynumber == 1)
            {
                reghotkey(handle, space, keymodifiers.ctrl, keys.d1);
            }
            else if (keynumber == 2)
            {
                reghotkey(handle, space, keymodifiers.ctrl, keys.d2);
            }
            else if (keynumber == 3)
            {
                reghotkey(handle, space, keymodifiers.ctrl, keys.d3);
            }
            else if (keynumber == 4)
            {
                reghotkey(handle, space, keymodifiers.ctrl, keys.d4);
            }
            else if (keynumber == 5)
            {
                reghotkey(handle, space, keymodifiers.ctrl, keys.d5);
            }
            else if (keynumber == 6)
            {
                reghotkey(handle, space, keymodifiers.ctrl, keys.d6);
            }
            else if (keynumber == 7)
            {
                reghotkey(handle, space, keymodifiers.ctrl, keys.d7);
            }
            else if (keynumber == 8)
            {
                reghotkey(handle, space, keymodifiers.ctrl, keys.d8);
            }
            else
            {
                reghotkey(handle, space, keymodifiers.ctrl, keys.d9);
            }
        }

 

 5)图形热键设置

 private void numbercbox_selectedindexchanged(object sender, eventargs e)
        {
//把配置文件设置numbercbox的选择值
            cutpicset.default.keynumber = numbercbox.selectedindex;
            cutpicset.default.save();
//先卸载原来注册的热键
            unreghotkey(handle, space);
//从新设置选择的热键
            sethotkey(numbercbox.selectedindex);
        }

 

4、截图界面设计

新建窗体cutpic,名称与之前的名称相对应,主要属性设置如下:

name:cutpic

windowstate:maximized

topmost:true

formborderstyle:none

5、截图功能实现

主要代码如下:

 private point m_ptstart;        //起始点位置
        private point m_ptcurrent;      //当前鼠标位置
        private point m_pttempformove;  //移动选框的时候临时用
        private rectangle m_rectclip;   //限定鼠标活动的区域
        private rectangle[] m_rectdots = new rectangle[8];  //八个控制点
        protected bool m_bmoving;
        protected bool m_bchangewidth;
        protected bool m_bchangeheight;
        protected bool m_bmousehover;
        private bool _isdrawed; /// 获取当前是否已经选择区域
        private image _image;
        ///
        /// 要裁剪的图像
        ///
        [description("要裁剪的图像"), category("customs")]
        public image image
        {
            get { return _image; }
            set
            {
                if (value == this._image) return;
                _image = value;
             //   this.clear();
            }
        }
        private color _maskcolor = color.fromargb(125, 0, 0, 0);
        ///
        /// 遮罩颜色
        ///
        [description("遮罩颜色"), category("customs")]
        public color maskcolor
        {
            get { return _maskcolor; }
            set
            {
                if (_maskcolor == value) return;
                _maskcolor = value;
                if (this._image != null) this.invalidate();
            }
        }
        private rectangle _selectedrectangle;/// 获取或设置悬着区域
       
        public cutpic()
        {
            setstyle(controlstyles.userpaint, true);  
            setstyle(controlstyles.allpaintinginwmpaint, true); // 禁止擦除背景.  
            setstyle(controlstyles.doublebuffer, true); // 双缓冲  

            initializecomponent();
        }

        private void cutpic_mousedown(object sender, mouseeventargs e)
        {
            if (this._image == null)
            {
                return;//image属性null或者已经锁定选择 直接返回
            }
            m_ptstart = e.location;
            m_bchangeheight = true;
            m_bchangewidth = true;

            //判断若不在限定范围内操作 返回
            m_rectclip = this.displayrectangle;
                size sz = this.size;
                sz = this.size;                
                m_rectclip.intersect(new rectangle(point.empty, sz));
                m_rectclip.width++; m_rectclip.height++;
                cursor.clip = rectangletoscreen(m_rectclip);
            

            if (toolspanel.visible==true)
            {
                toolspanel.visible = false;
            }
            //如果 已经选择区域 若鼠标点下 判断是否在控制顶点上
            if (this._isdrawed)
            {
                this._isdrawed = false; //默认表示 要更改选取设置 清楚isdrawed属性
                if (m_rectdots[0].contains(e.location))
                {
                    m_ptstart.x = this._selectedrectangle.right;
                    m_ptstart.y = this._selectedrectangle.bottom;
                }
                else if (m_rectdots[1].contains(e.location))
                {
                    m_ptstart.y = this._selectedrectangle.bottom;
                    m_bchangewidth = false;
                }
                else if (m_rectdots[2].contains(e.location))
                {
                    m_ptstart.x = this._selectedrectangle.x;
                    m_ptstart.y = this._selectedrectangle.bottom;
                }
                else if (m_rectdots[3].contains(e.location))
                {
                    m_ptstart.x = this._selectedrectangle.right;
                    m_bchangeheight = false;
                }
                else if (m_rectdots[4].contains(e.location))
                {
                    m_ptstart.x = this._selectedrectangle.x;
                    m_bchangeheight = false;
                }
                else if (m_rectdots[5].contains(e.location))
                {
                    m_ptstart.x = this._selectedrectangle.right;
                    m_ptstart.y = this._selectedrectangle.y;
                }
                else if (m_rectdots[6].contains(e.location))
                {
                    m_ptstart.y = this._selectedrectangle.y;
                    m_bchangewidth = false;
                }
                else if (m_rectdots[7].contains(e.location))
                {
                    m_ptstart = this._selectedrectangle.location;
                }
                else if (this._selectedrectangle.contains(e.location))
                {
                    m_bmoving = true;
                    m_bchangewidth = false;
                    m_bchangeheight = false;
                }
                else { this._isdrawed = true; }   //若以上条件不成立 表示不需要更改设置
            }
        }

        private void cutpic_mouseclick(object sender, mouseeventargs e)
        {
            if (mousebuttons.right==e.button)
            {
                this.dialogresult = dialogresult.ok;
                this.close();
            }
        }

        private void cutpic_paint(object sender, painteventargs e)
        {
            graphics g = e.graphics;
            if (_image!=null)
            {
                  g.drawimage(this._image,0,0,this._image.width,this._image.height);//原图
                  using (solidbrush sb = new solidbrush(this._maskcolor))
                  {
                      g.fillrectangle(sb, this.clientrectangle);//遮罩
                  }
                  if (!this._selectedrectangle.isempty)
                      this.drawselectedrectangle(g);//选框
            }
            setpanlelocation();
        }

        private void cutpic_load(object sender, eventargs e)
        {
            for (int i = 0; i < 8; i++)
            {
                m_rectdots[i].size = new size(5, 5);
            }        
                          
            m_pttempformove = this.displayrectangle.location;
          
        }

        private void cutpic_mousemove(object sender, mouseeventargs e)
        {
            m_ptcurrent = e.location;
            if (this._image == null)
            {
                return;
            }
            if (this._isdrawed)
            {//如果已经绘制 移动过程中判断是否需要设置鼠标样式
                this.setcursorstyle(e.location);
            }
            else if (e.button == mousebuttons.left)
            {//否则可能表示在选择区域或重置大小
                if (m_bchangewidth)
                {//是否允许选区宽度改变 如重置大小时候 拉动上边和下边中点时候
                    this._selectedrectangle.x = e.location.x > m_ptstart.x ? m_ptstart.x : e.location.x;
                    this._selectedrectangle.width = math.abs(e.location.x - m_ptstart.x);
                }
                if (m_bchangeheight)
                {
                    this._selectedrectangle.y = e.location.y > m_ptstart.y ? m_ptstart.y : e.location.y;
                    this._selectedrectangle.height = math.abs(e.location.y - m_ptstart.y);
                }
                if (m_bmoving)
                {//如果是移动选区 判断选区移动范围
                    int tempx = m_pttempformove.x + e.x - m_ptstart.x;
                    int tempy = m_pttempformove.y + e.y - m_ptstart.y;
                    
                    if (tempx < 0) tempx = 0;
                        if (tempy < 0) tempy = 0;
                        if (this._selectedrectangle.width + tempx >= m_rectclip.width) tempx = m_rectclip.width - this._selectedrectangle.width - 1;
                        if (this._selectedrectangle.height + tempy >= m_rectclip.height) tempy = m_rectclip.height - this._selectedrectangle.height - 1;
                   
                    this._selectedrectangle.x = tempx;
                    this._selectedrectangle.y = tempy;
                }
                this.invalidate();
            }
            else if (!this._isdrawed)
            {
                this.invalidate();//否则 在需要绘制放大镜并且还没有选好区域同时 都重绘
            }
        }
        ///
        /// 判断鼠标当前位置显示样式
        ///
        /// 鼠标坐标
        protected virtual void setcursorstyle(point pt)
        {
            if (m_rectdots[0].contains(pt) || m_rectdots[7].contains(pt))
                this.cursor = cursors.sizenwse;
            else if (m_rectdots[1].contains(pt) || m_rectdots[6].contains(pt))
                this.cursor = cursors.sizens;
            else if (m_rectdots[2].contains(pt) || m_rectdots[5].contains(pt))
                this.cursor = cursors.sizenesw;
            else if (m_rectdots[3].contains(pt) || m_rectdots[4].contains(pt))
                this.cursor = cursors.sizewe;
            else if (this._selectedrectangle.contains(pt))
                this.cursor = cursors.sizeall;
            else
                this.cursor = cursors.default;
        }

        private void cutpic_mouseup(object sender, mouseeventargs e)
        {
            this._isdrawed = !this._selectedrectangle.isempty;
            m_pttempformove = this._selectedrectangle.location;
            m_bmoving = false;
            m_bchangewidth = false;
            m_bchangeheight = false;
            cursor.clip = rectangle.empty;
            toolspanel.visible = true;
            this.invalidate();

            
           
        }

        public void setpanlelocation()
        {
            toolspanel.left = this._selectedrectangle.left + this._selectedrectangle.width - toolspanel.width;
            toolspanel.top =  this._selectedrectangle.top+this._selectedrectangle.height+5;
        }


        ///
        /// 绘制选框
        ///
        /// 绘图表面
        protected virtual void drawselectedrectangle(graphics g)
        {
            m_rectdots[0].y = m_rectdots[1].y = m_rectdots[2].y = this._selectedrectangle.y - 2;
            m_rectdots[5].y = m_rectdots[6].y = m_rectdots[7].y = this._selectedrectangle.bottom - 2;
            m_rectdots[0].x = m_rectdots[3].x = m_rectdots[5].x = this._selectedrectangle.x - 2;
            m_rectdots[2].x = m_rectdots[4].x = m_rectdots[7].x = this._selectedrectangle.right - 2;
            m_rectdots[3].y = m_rectdots[4].y = this._selectedrectangle.y + this._selectedrectangle.height / 2 - 2;
            m_rectdots[1].x = m_rectdots[6].x = this._selectedrectangle.x + this._selectedrectangle.width / 2 - 2;

            g.drawimage(this._image, this._selectedrectangle, this._selectedrectangle, graphicsunit.pixel);
            g.drawrectangle(pens.cyan, this._selectedrectangle.left, this._selectedrectangle.top, this._selectedrectangle.width - 1, this._selectedrectangle.height - 1);
            foreach (rectangle rect in m_rectdots)
                g.fillrectangle(brushes.yellow, rect);
            string str = string.format("x:{0} y:{1} w:{2} h:{3}",
                this._selectedrectangle.left, this._selectedrectangle.top, this._selectedrectangle.width, this._selectedrectangle.height);
            size szstr = g.measurestring(str, this.font).tosize();
            point ptstr = new point(this._selectedrectangle.left, this._selectedrectangle.top - szstr.height - 5);
            if (ptstr.y < 0) ptstr.y = this._selectedrectangle.top + 5;
            if (ptstr.x + szstr.width > this.width) ptstr.x = this.width - szstr.width;
            using (solidbrush sb = new solidbrush(color.fromargb(125, 0, 0, 0)))
            {
                g.fillrectangle(sb, new rectangle(ptstr, szstr));
                g.drawstring(str, this.font, brushes.white, ptstr);
            }
        }

        private void savebt_click(object sender, eventargs e)
        {
            savefiledialog savefiledialog = new savefiledialog();
            savefiledialog.filename = datetime.now.tostring("yyyymmddhhmmss");
            savefiledialog.filter = "png|*.png|bmp|*.bmp|jpg|*.jpg|gif|*.gif";
            if (savefiledialog.showdialog() != dialogresult.cancel)
            {
                system.drawing.rectangle croparea = new system.drawing.rectangle(_selectedrectangle.x, _selectedrectangle.y, _selectedrectangle.width, _selectedrectangle.height);
                bitmap bmpimage = new bitmap(this._image);
                bitmap bmpcrop = bmpimage.clone(croparea, bmpimage.pixelformat);
                bmpcrop.save(savefiledialog.filename);
                this.dialogresult = dialogresult.ok;
                this.close();
            }
            else
            {
                this.focus();
            }
        }
       

        private void cutpic_mousedoubleclick(object sender, mouseeventargs e)
        {
            if (this._selectedrectangle.contains(e.location))
            {
                //复制图片到剪切板
                system.drawing.rectangle croparea = new system.drawing.rectangle(_selectedrectangle.x, _selectedrectangle.y, _selectedrectangle.width, _selectedrectangle.height);
                bitmap bmpimage = new bitmap(this._image);
                bitmap bmpcrop = bmpimage.clone(croparea, bmpimage.pixelformat);
                clipboard.setimage(bmpcrop);
                this.dialogresult = dialogresult.ok;
                this.close();
            }
        }
//如果按下esc键退出截图功能
        private void cutpic_keyup(object sender, keyeventargs e)
        {
            if (e.keyvalue==27)
            {
                this.dialogresult = dialogresult.ok;
                this.close();
            }
        }

 

这样截图功能就已经实现了。源代码下载,请

 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网