当前位置: 首页 > 编程日记 > 正文

C# GDI+ 简单绘图 (三)

感谢大家的支持,这几天从早忙到晚,一个字累呀!!!现在挺困的,但是又不习惯这么早睡觉,哎~~还是利用这个时间继续来写第三篇吧.
  前两篇已经基本向大家介绍了绘图的基本知识.那么,我就用我们上两篇所学的,做几个例子.
  我们先来做一个简单的----仿QQ截图,关于这个的例子其实网上已经有这方面的资料了,但是为了文章的完整性,还是觉得有必要讲解.
  我们先来看一下效果:


                                                                                                                  (图1)
                                                      20083191642.JPG
                                                                                                                     (图2)

  接下来看看这是如何做到的. 
  思路:聊天窗体上有一个截图按钮,点击按钮后,程序将整个屏幕画在一个新的全屏窗体上,然后显示这个窗体.因为是全屏的窗体,并且隐藏了菜单栏、工具 栏等,所以在我们看来就好像是一个桌面的截图,然后在这个新窗体上画矩形,最后保存矩形中的内容并显示在原来的聊天窗体中.
  步骤:
  A.新建一个窗体.命名为Catch.然后设置这个窗体的FormBorderStyle为None,WindowState为Maximized.
  B.我们对代码进行编辑:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Client
{
    
public partial class Catch : Form
    
{
        
public Catch()
        
{
            InitializeComponent();
        }


        
用户变量

        
//窗体初始化操作
        private void Catch_Load(object sender, EventArgs e)
        
{
            
this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
            
this.UpdateStyles();
            
//以上两句是为了设置控件样式为双缓冲,这可以有效减少图片闪烁的问题,关于这个大家可以自己去搜索下
            originBmp = new Bitmap(this.BackgroundImage);//BackgroundImage为全屏图片,我们另用变量来保存全屏图片
        }


        
//鼠标右键点击结束截图
        private void Catch_MouseClick(object sender, MouseEventArgs e)
        
{
            
if (e.Button == MouseButtons.Right)
            
{
                
this.DialogResult = DialogResult.OK;
                
this.Close();
            }

        }


        
//鼠标左键按下时动作
        private void Catch_MouseDown(object sender, MouseEventArgs e)
        
{
            
if (e.Button == MouseButtons.Left)
            
{
                
if (!CatchStart)
                
{//如果捕捉没有开始
                    CatchStart = true;
                    DownPoint 
= new Point(e.X, e.Y);//保存鼠标按下坐标
                }

            }

        }


        
private void Catch_MouseMove(object sender, MouseEventArgs e)
        
{
            
if (CatchStart)
            
{//如果捕捉开始
                Bitmap destBmp = (Bitmap)originBmp.Clone();//新建一个图片对象,并让它与原始图片相同
                Point newPoint = new Point(DownPoint.X, DownPoint.Y);//获取鼠标的坐标
                Graphics g = Graphics.FromImage(destBmp);//在刚才新建的图片上新建一个画板
                Pen p = new Pen(Color.Blue,1);
                
int width = Math.Abs(e.X - DownPoint.X), 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;
                }

                CatchRect 
= new Rectangle(newPoint,new Size(width,height));//保存矩形
                g.DrawRectangle(p,CatchRect);//将矩形画在这个画板上
                g.Dispose();//释放目前的这个画板
                p.Dispose();
                Graphics g1 
= this.CreateGraphics();//重新新建一个Graphics类
                
//如果之前那个画板不释放,而直接g=this.CreateGraphics()这样的话无法释放掉第一次创建的g,因为只是把地址转到新的g了.如同string一样
                g1 = this.CreateGraphics();//在整个全屏窗体上新建画板
                g1.DrawImage(destBmp,new Point(0,0));//将刚才所画的图片画到这个窗体上
                
//这个也可以属于二次缓冲技术,如果直接将矩形画在窗体上,会造成图片抖动并且会有无数个矩形.
                g1.Dispose();
                destBmp.Dispose();
//要及时释放,不然内存将会被大量消耗
                
            }

        }


        
private void Catch_MouseUp(object sender, MouseEventArgs e)
        
{
            
if (e.Button == MouseButtons.Left)
            
{
                
if (CatchStart)
                
{
                    CatchStart 
= false;
                    CatchFinished 
= true;
                  
                }

            }

        }


        
//鼠标双击事件,如果鼠标位于矩形内,则将矩形内的图片保存到剪贴板中
        private void Catch_MouseDoubleClick(object sender, MouseEventArgs e)
        
{
            
if (e.Button == MouseButtons.Left&&CatchFinished)
            
{
                
if (CatchRect.Contains(new Point(e.X, e.Y)))
                
{
                    Bitmap CatchedBmp 
= new Bitmap(CatchRect.Width, CatchRect.Height);//新建一个于矩形等大的空白图片
                    Graphics g = Graphics.FromImage(CatchedBmp);
                    g.DrawImage(originBmp, 
new Rectangle(00, CatchRect.Width, CatchRect.Height), CatchRect, GraphicsUnit.Pixel);
                    
//把orginBmp中的指定部分按照指定大小画在画板上
                    Clipboard.SetImage(CatchedBmp);//将图片保存到剪贴板
                    g.Dispose();
                    CatchFinished 
= false;
                    
this.BackgroundImage = originBmp;
                    CatchedBmp.Dispose();
                    
this.DialogResult = DialogResult.OK;
                    
this.Close();
                }

            }

        }

    }

}

C.创建了Catch窗体后,我们在截图按钮(位于聊天窗体上)上加入以下事件:

        private void bCatch_Click(object sender, EventArgs e)
        
{

            
if (bCatch_HideCurrent.Checked)
            
{
                
this.Hide();//隐藏当前窗体
                Thread.Sleep(50);//让线程睡眠一段时间,窗体消失需要一点时间
                Catch CatchForm = new Catch();
                Bitmap CatchBmp 
= new Bitmap(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height);//新建一个和屏幕大小相同的图片         
                Graphics g = Graphics.FromImage(CatchBmp);
                g.CopyFromScreen(
new Point(00), new Point(00), new Size(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height));//保存全屏图片
                CatchForm.BackgroundImage = CatchBmp;//将Catch窗体的背景设为全屏时的图片
                if (CatchForm.ShowDialog() == DialogResult.OK)
                
{//如果Catch窗体结束,就将剪贴板中的图片放到信息发送框中
                    IDataObject iData = Clipboard.GetDataObject();
                    DataFormats.Format myFormat 
= DataFormats.GetFormat(DataFormats.Bitmap);
                    
if (iData.GetDataPresent(DataFormats.Bitmap))
                    
{
                        richtextbox1.Paste(myFormat);
                        Clipboard.Clear();
//清除剪贴板中的对象
                    }

                    
this.Show();//重新显示窗体
                }

            }


        }
这样我们的截图功能便完成了.
  我想对于初学者来说如何消去第一次绘制的图片是个比较困难的问题.如果没有采取措施,你会发现只要你鼠标移动,就会画一个矩形,这样便会出现N多的矩形,而我们只是要最后的那一个.
  一般解决这种问题的方法有两种:
  1.就是在绘制第二个图形时,我们先用与底色相同的颜色将上次绘制的图形重新绘制一下.但这往往需要底色为纯色时使用.
  2.我们并不直接将图形画在画板上,我们用一个图片A来保存原画板上的图片.然后再新建一个与图片A相同的图片B,将我们要绘制的图形画在该图片B 上,然后再将该图片B画在画板上.这样图片A并没有被改变.于是第二次画的时候我们还是同样新建一个与图片A相同的图片进行绘制.那么上一次的图形就不会 被保留下来.问题也就解决了.

  下一次,向大家介绍如何做一个仿windows画板的程序.

转载于:https://www.cnblogs.com/zzh1236/archive/2012/06/29/2570050.html

相关文章:

用java实现一个简易自动提款机

用java实现一个简易自动提款机&#xff0c;且有以下要求 如何实现呢&#xff1f;首先&#xff0c;我们定义一个用户类User&#xff0c;同时根据要求设计好属性(本人部分命名没有使用驼峰命名法&#xff0c;不够规范)。因为一个人可能有多个卡&#xff0c;卡号又不能重复&#x…

mysql java jdbc 如何 update select

2019年8月6日17:28:07 sql 不知道怎么写&#xff0c;也没去查&#xff0c;因为需求可能中途需要修改值&#xff0c;有点麻烦 直接用jdbc实现。 查询出来的值&#xff0c;直接根据update条件更新&#xff0c;写在一个方法里 public static void GetWeiLiaoMsg(String day) {try …

2000DC和DNS迁移到2003 R2

2000DC和DNS迁移到2003 R2 实验环境&#xff1a;一台TPLINK路由器&#xff0c;三台电脑&#xff0c;以下简称A&#xff0c;B&#xff0c;C。A当作公司的2000DC和DNS服务器。B当作公司要升级的2003R2 DC。C 当作客户机&#xff0c;测试用。1&#xff0e; 对TPLINK路由器&…

SAP EWM 代码实现Transportation Unit(TU)的创建

在EWM中很少有创建或者修改业务对象的BAPI存在&#xff0c;更多的是通过很多面向对象的类方法来实现。 以下这个简单的创建TU应该能很好的体现SCM平台中的OO特性。 REPORT yewm_tu_creation NO STANDARD PAGE HEADING. TYPES: BEGIN OF lty_key_wrk, tu_num TY…

libcurl 客户端实例

参考库 libftp (though its in C)ftplib (again, looks like C)libCurl seems to have FTP capabilities.ace源码&#xff1a;main.c #include <stdio.h> #include <string.h>#include <curl/curl.h> #include <sys/types.h> #include <sys/stat.h&…

哈夫曼树的生成及哈夫曼编码

首先构造哈夫曼树结构体&#xff0c;初始化哈夫曼树的四个无符号整型域&#xff0c;输入文本&#xff0c;统计各个字符的权值&#xff0c;然后构建哈夫曼树&#xff0c;从根到叶子逆向求哈夫曼树的编码。 #include"stdio.h" #include"string.h" #include&…

shiro(2)-架构与配置

认证就是用户确认身份的过程&#xff0c;确认登录的用户身份能够操作的内容。 使用shiro认证分为以下几个步骤&#xff1a; 1&#xff0c;得到主体的认证和凭据。 // lets login the current user so we can check against roles and permissions:if (!currentUser.isAuthentic…

unity中的UI状态机,用于各界面之间的切换和跳转

首先感谢姜雪松先生&#xff0c;大家可以去他的博客查看注释以及代码等&#xff0c;http://jxwgame.blog.51cto.com/943299/1613585 言归正传&#xff1a; 1.在开发项目的过程中&#xff0c;总是会遇到这样的问题&#xff0c;从一个界面跳转到另外一个界面&#xff0c;每次操作…

【转载】Session服务器配置指南与使用经验

作者&#xff1a;张子秋出处&#xff1a;http://www.cnblogs.com/zhangziqiu/ 原文链接&#xff1a;http://www.cnblogs.com/zhangziqiu/archive/2009/03/26/sessionserver.htm一、摘要所有Web程序都会使用Session保存数据. 使用独立的Session服务器可以解决负载均衡场景中的Se…

如何使用jdbc连接数据库

如何使用jdbc连接数据库 数据库是一个有组织的数据集合。数据库管理系统以一种与数据库格式一致的方式&#xff0c;提供了存储和组织数据的机制。数据库管理系统允许在不考虑内部数据表示的情况下访问和存储数据。 java程序使用JDBC API与数据库通信&#xff0c;并用它操纵数…

Mysql配置查询

查看mysql数据库的线程数&#xff1a; show global status like Thread%; 如果我们在MySQL服务器配置文件中设置了thread_cache_size&#xff0c;当客户端断开之后&#xff0c;服务器处理此客户的线程将会缓存起来以响应下一个客户而不是销毁(前提是缓存数未达上限)。Threads_c…

自我暗示的三大规律

伟人之所以伟大&#xff0c;是因为别人放弃时&#xff0c;他却在坚持。理解暗示的三大规律后&#xff0c;你就会清楚地知道&#xff0c;为什么在别人放弃的时候&#xff0c;你仍然要坚持。 自我暗示第一规律&#xff1a;重复 经常重复一种思想会产生信念&#xff0c;进而变得坚…

python爬虫入门urllib库的使用

urllib库的使用&#xff0c;非常简单。 import urllib2response urllib2.urlopen("http://www.baidu.com") print response.read() 只要几句代码就可以把一个网站的源代码下载下来。 官方文档&#xff1a;https://docs.python.org/2/library/urllib2.html urllib2.u…

maven如何在eclipse上加载

maven如何在eclipse上安装和使用 maven是Apache旗下的定级开源工具,在项目管理方面有强大的能力。Maven 除了以程序构建能力为特色之外&#xff0c;还提供高级项目管理工具。由于 Maven 的缺省构建规则有较高的可重用性&#xff0c;所以常常用两三行 Maven 构建脚本就可以构建…

初步判断内存泄漏方法

有时候&#xff0c;内存泄漏不明显&#xff0c;或者怀疑系统有内存泄漏&#xff0c;我们可以通过下面介绍的方法初步确认系统是否存在内存泄漏。首先在Java命令行中增加-verbose:gc参数&#xff0c;然后重新启动java进程。当系统运行过程中,JVM进行垃圾回收的时候&#xff0c;会…

com组件和一般dll的区别

这阵子在想一个需要利用com组件的小程序怎么做&#xff0c;突然想起上次去面试的时候考官问过autocad开发时为什么要利用com&#xff0c;而不采用一般的dll呢&#xff1f; 到google上查了一下&#xff0c;许多人也问了一样的问题&#xff1a;&#xff09; 用com来写程序…

WinCE6.0 修改开机Logo方法集锦(二)

中秋假期已过&#xff0c;回来继续该博文主题。今天讲解第二种方法&#xff0c;将Logo图片的数据写入到Nand Flash中&#xff0c;在启动初始化LCD的时候&#xff0c;从固定的地址将数据读出并填充到显示缓存中。<?xml:namespace prefix o ns "urn:schemas-microsoft…

[动态dp]线段树维护转移矩阵

背景&#xff1a;czy上课讲了新知识&#xff0c;从未见到过&#xff0c;总结一下。 所谓动态dp&#xff0c;是在动态规划的基础上&#xff0c;需要维护一些修改操作的算法。 这类题目分为如下三个步骤&#xff1a;&#xff08;都是对于常系数齐次递推问题&#xff09; 1先不考虑…

原始ajax方式调用asp.net后台方法

aspx页面&#xff1a; <% Page Language"C#" AutoEventWireup"true" CodeFile"Data.aspx.cs" Inherits"Data" %><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xht…

洛谷P4480 【[BJWC2018]餐巾计划问题】

这道题和网络流 \(24\) 题中的餐巾计划的确不一样, \([\) \(BJWC\) \(2018\) \(]\) 餐巾计划问题的数据范围更大。 一个餐厅在相继的 \(n\) 天里&#xff0c;每天需用的餐巾数不尽相同。假设第 \(i\) 天 \((\) \(i\) \(\) \(1\) \(,\) \(2\) \(,\) \(...\) \(,\) \(n\) \()\)需…

灵活使用java反射简化servlet

在我们初学jsp的时候&#xff0c;我们通常将java代码放到jsp页面

第四篇 Gallery控件

直奔主题~&#xff01; 结构如图&#xff1a; main.xml代码: <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:orientation"vertical" android:la…

macaca之app-inspector

简单介绍 之前已经将macaca的环境搭建好了&#xff0c;现在就需要进行元素的定位&#xff0c;这里使用app-inspector&#xff0c;然后进行自动化脚本的编写。 实际操作 一、安装app-inspector npm i app-inspector -g 安装成功确保如下命令中有手机或模拟器的连接&#xff0c;可…

visual-reasoning 笔记

目录 整理最近学习 visual-reasoning的笔记 1. 关注 ACL、EMNLP、NAACLI等会议文章 未开始 2. Cyc项目 2.1 cyc知识库介绍&#xff1a; ​ 该知识库包含了320w条人类断言&#xff0c;30w概念&#xff0c;15000谓词。 ​ Cyc知识库中表示的知识一般形如“每棵树都是植物”、“植…

使用beanutil简化request值的接收

在刚开始学习java web的时候&#xff0c;我们想要接收从其他页面传过来的值常使用以下的语句 request.setCharacterEncoding("UTF-8");String Kind1 request.getParameter("foodKind");String Code1 request.getParameter("foodCode");String…

命令行编译运行CSharp文件

命令行编译运行CSharp文件 找到csc.exe所在的路径。如我本机上为“C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727”在环境变量里增加变量CSC_HOME&#xff0c;值为以上路径。在PATH变量的值中加入%CSC_HOME%在cmd中进入要编译的cs文件所在的文件夹输入命令csc 文件名&#xf…

大话IT职场之工作和生活的平衡

每一个职场人都有自己的规划&#xff0c;特别是IT人员&#xff0c;基本都在想我要几个月掌握这门技术或语言&#xff0c;我要多久能带团队&#xff0c;我多长时间可以做到管理岗位&#xff0c;技术经理、技术总监等&#xff0c;每个人基本都充斥着这样的想法。但是否同时也在考…

安装和使用git遇到的问题总结

一&#xff0c;centos7下安装(因为centos7下用yum安装git的版本太低了&#xff0c;所以只能下载源代码&#xff0c;然后用源代码安装&#xff09; 下载编译工具 yum -y groupinstall "Development Tools" 下载依赖包 yum -y install zlib-devel perl-ExtUtils-MakeM…

Linux系统文本命令快速登录与退出

Linux是一个多用户的操作系统&#xff0c;用户要使用该系统&#xff0c;首先必须登录系统&#xff0c;使用完系统后&#xff0c;必须退出系统。用户登录系统时&#xff0c;为了使系统能够识别自己&#xff0c;必须输入用户名和密码&#xff0c;经系统验证无误后方能进入系统。在…

调试 后台 ajax post 对应的php的方法

在对应的javascript中 $.post("<?php echo ROOTURL ?>/Service/SetPlayerStartCord.php", "IP192.168.0.32&startCord_X400&startCord_Y30", function(data){!!!alert("Data Loaded: " data); }转载于:https://www.cnblogs.com…