C# GDI+ 实现橡皮筋技术

应该有很多人都在寻找这方面的资料,看看下面我做的,或许对你会有所帮助,但愿如此。

为了实现橡皮筋技术,我用了两种方法:
    第一种是利用ControlPaint.DrawReversibleLine(Point start,Point end, Color BackColor)方法,原理:在屏幕上指定的起始点和结束点内绘制具有指定背景色的可逆线,再次绘制同一条线会逆转该方法的结果。使用该方法绘制线类似于反转屏幕的一个区域,不过它提供了更好的性能适用于更广泛的颜色。
    要注意的是这的start起始点和end终止点是相对于屏幕的,因此我用PointTOScreen(Point p)方法进行转换。
    遗憾的是,在鼠标拖动的时候,画出来的变换(即一段线段,在我的研究领域内,我称带线冒的线段为变换)不带线冒。为了画出变换,只有采用在左键按下时重画来实现(如果你不需要线冒,把MouseDown()方法中的Invalidate()注释掉就行了)。因为在采用DrawReversibleLine()方法时用的是背景色backColor=(a,r,g,b),它能自动对颜色进行反转,而采用在左键按下时重画就需要用背景色的反转颜色reversebackColor=(a’,r’,g’,b’),那么怎样获取背景色的反转颜色呢?我采用的是用255减原来的背景色的r,g,b,而透明度不变,即a’=a;r’=255-r;g’=255-g;b’=255-b;然后用这种颜色定义的画笔来重画。

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using System.Drawing.Drawing2D;//包含这个高级二维图形命名空间namespace ReverseLines{    public partial class Form1 : Form    {        public Form1()        {            InitializeComponent();            //激活双缓冲技术            SetStyle(ControlStyles.UserPaint, true);            SetStyle(ControlStyles.AllPaintingInWmPaint, true);            SetStyle(ControlStyles.DoubleBuffer, true);        }        private Point[][] tranGroup = new Point[1000][];//变换组        private int tranNumb = 0;//变换序号        private int pushNumb = 0;//左键按下情况:0为开始画变换,1为结束        private Point curP;//存储变换时鼠标的当前点        private Point startP, oldP;//变换的起点和鼠标移动时的当前点        private Graphics g0,g3;//窗口绘图面和采用双缓冲时的临时绘图面        private Point endPoint;//存储右键按下时放弃绘制相连变换的鼠标点        private Color clr,clr1;//获取窗体背景色和反转背景色        private Pen p;//重画变换时所用的笔        private Bitmap bitmap = null;//双缓冲时用的位图        private void Form1_Paint(object sender, PaintEventArgs e)        {            g0 = e.Graphics;            bitmap = new Bitmap(ClientSize.Width, ClientSize.Height);//创建临时位图            g3 = Graphics.FromImage(bitmap);//从位图创建绘图面            g3.Clear(this.BackColor);//清除背景色            g3.SmoothingMode = SmoothingMode.AntiAlias;//设置抗锯齿平滑模式            //在临时位图上重画变换,抗锯齿,带线冒            for (int i = 0; i = 999)            {                pushNumb = 0;                Capture = false;                return;            }            //左键按下            if (e.Button == MouseButtons.Left)            {                if (pushNumb == 0)//判断是否是折线的开始                {                    if (endPoint.X != e.X || endPoint.Y != e.Y)                    {                        pushNumb++;                        startP.X = e.X;                        startP.Y = e.Y;                        oldP.X = e.X;                        oldP.Y = e.Y;                        Capture = true;//捕获鼠标                    }                }                else if (pushNumb == 1)//如果不是一段新的折线的开始                {                    ControlPaint.DrawReversibleLine(PointToScreen(startP), PointToScreen(new Point(e.X, e.Y)), clr);                    ControlPaint.DrawReversibleLine(PointToScreen(startP), PointToScreen(new Point(e.X, e.Y)), clr);                                                           //把变换存入变换组中                    curP.X = e.X;                    curP.Y = e.Y;                    tranGroup[tranNumb][0] = startP;                    tranGroup[tranNumb][1] = curP;                    tranNumb++;                    startP.X = e.X;                    startP.Y = e.Y;                    //存储一段折线的最后一个点的坐标                    endPoint.X = e.X;                    endPoint.Y = e.Y;                }                          }            //右键按下            if (e.Button == MouseButtons.Right)            {                //变换数超过变换组最大限度                if (pushNumb == 0)                    return;                //变换数没有超过变换组最大限度                pushNumb = 0;//一段折线结束                Capture = false;//释放鼠标                //绘制最后一个变换                ControlPaint.DrawReversibleLine(PointToScreen(startP), PointToScreen(new Point(e.X, e.Y)), clr);            }            //失效重画,为抗锯齿            Invalidate();            g2.Dispose();        }        private void Form1_MouseMove(object sender, MouseEventArgs e)        {            Graphics g1 = CreateGraphics();            //左键按下并移动鼠标            if (pushNumb == 1)            {                if (oldP.X != e.X || oldP.Y != e.Y)                {                    //在屏幕上指定的起始点和结束点内绘制具有指定背景色的可逆线                    //再次绘制同一条线会逆转该方法的结果。使用该方法绘制线类似于反转屏幕的一个区域,                    //不过它提供了更好的性能适用于更广泛的颜色。                    ControlPaint.DrawReversibleLine(PointToScreen(startP), PointToScreen(oldP), clr);                    ControlPaint.DrawReversibleLine(PointToScreen(startP), PointToScreen(new Point(e.X, e.Y)), clr);                                       //存储一个变换的终点,作为下一变换的起点                    oldP.X = e.X;                    oldP.Y = e.Y;                }            }            g1.Dispose();        }        //释放资源        private void Form1_FormClosed(object sender, FormClosedEventArgs e)        {            g3.Dispose();            bitmap.Dispose();            g0.Dispose();        }    }}

登录后复制

第二种是直接利用背景色来绘制鼠标拖动时需要被擦除的变换,而用当前画笔来绘制一个确定的变换。采用这种方式可以使鼠标被拖动时画出来的变换带线冒。

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using System.Drawing.Drawing2D;namespace Shiqu2{    public partial class Form1 : Form    {        public Form1()        {            InitializeComponent();            //激活双缓冲技术            SetStyle(ControlStyles.UserPaint, true);            SetStyle(ControlStyles.AllPaintingInWmPaint, true);            SetStyle(ControlStyles.DoubleBuffer, true);        }        private Point[][] tranGroup = new Point[1000][];//变换组        private int tranNumb = 0;//变换序号        private int pushNumb = 0;//左键按下情况:0为开始画变换,1为结束        private Point curP;//存储变换时鼠标的当前点        private Point startP, oldP;//变换的起点和鼠标移动时的当前点        private Graphics g0, g3;//窗口绘图面和采用双缓冲时的临时绘图面        public Pen curPen;//一个变换确定并要绘制时所用的画笔        private Point endPoint;//存储右键按下时放弃绘制相连变换的鼠标点        private Color clr;//获取窗体背景色        private Pen p;//重画变换时所用的笔        private Bitmap bitmap = null;//双缓冲时用的位图        private void Form1_Paint(object sender, PaintEventArgs e)        {            g0 = e.Graphics;            bitmap = new Bitmap(ClientSize.Width, ClientSize.Height);//创建临时位图            g3 = Graphics.FromImage(bitmap);//从位图创建绘图面            g3.Clear(this.BackColor);//清除背景色            g3.SmoothingMode = SmoothingMode.AntiAlias;//设置抗锯齿平滑模式            //在临时位图上重画已有的变换,抗锯齿,带线冒            for (int i = 0; i = 999)            {                pushNumb = 0;                Capture = false;                return;            }            //左键按下            if (e.Button == MouseButtons.Left)            {                if (pushNumb == 0)//判断是否是折线的开始                {                    if (endPoint.X != e.X || endPoint.Y != e.Y)                    {                        pushNumb++;                        startP.X = e.X;                        startP.Y = e.Y;                        oldP.X = e.X;                        oldP.Y = e.Y;                        Capture = true;//捕获鼠标                    }                                   }                else if (pushNumb == 1)//如果不是一段新的折线的开始                {                    g2.DrawLine(curPen, startP, new Point(e.X, e.Y));                    //把变换存入变换组中                    curP.X = e.X;                    curP.Y = e.Y;                    tranGroup[tranNumb][0] = startP;                    tranGroup[tranNumb][1] = curP;                    tranNumb++;                    startP.X = e.X;                    startP.Y = e.Y;                    //存储一段折线的最后一个点的坐标                    endPoint.X = e.X;                    endPoint.Y = e.Y;                }            }            //右键按下            if (e.Button == MouseButtons.Right)            {                //变换数超过变换组最大限度                if (pushNumb == 0) return;                //变换数没有超过变换组最大限度                pushNumb = 0;//一段折线结束                Capture = false;//释放鼠标            }            //失效重画,为抗锯齿            Invalidate();            g2.Dispose();        }        private void Form1_MouseMove(object sender, MouseEventArgs e)        {            Graphics g1 = CreateGraphics();            //左键按下并移动鼠标            if (pushNumb ==1)            {                if (oldP .X !=e.X||oldP .Y !=e.Y)                {                    g1.DrawLine(p, startP, oldP);//用背景色绘制原来的变换                    g1.DrawLine(curPen, startP, new Point(e.X, e.Y));//用当前画笔绘制当前变换                    //用当前绘制已有的变换,防止它们被擦除                    for (int i = 0; i 

  上述两种方法都采用了双缓冲技术:先创建一个大小和客户区一样的位图bitmap,再用位图创建一个临时的绘图面g3,然后在g3上绘制变换,画完之后再用窗体绘图面g把位图画出来。
  抗锯齿技术:只需一句话g3.SmoothingMode = SmoothingMode.AntiAlias,但要注意的是在左键按下和鼠标拖动的情况下不能使用抗锯齿技术。

登录后复制

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2445756.html

(0)
上一篇 2025年3月3日 16:13:50
下一篇 2025年3月1日 11:54:44

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • 子对话框的创建与销毁

    1.显示对话框 1.1显示模式对话框: CDialogDemo dlg;dlg.DoModal(); 登录后复制 1.2 显示非模式对话框: CDialogDemo *dlg=new CDialogDemo(this); dlg->C…

    编程技术 2025年3月3日
    200
  • C++静态成员与常成员的使用

    1、 实验目的 (1)学习静态成员的使用 (2)学习常成员的使用 (3)掌握静态数据成员与常数据成员的初始化 2、实验内容 (1)某商店经销一种货物,货物成箱购进,成箱卖出,购进和卖出时以重量为单位,各箱的重量不一样,因此,商店需要记录下目…

    2025年3月3日
    200
  • 用C++对C++语法格式进行分析

    前言 最近c++项目需要用到脚本,这就关系到如何绑定对象到脚本运行环境。因使用到多套脚本语言,所以现有的绑定技术,都不能满足需求。所以只能寻求解析c++的头文件,再根据描述进行绑定。起初发现boost有一套,但boost实在太臃肿了,对项目…

    编程技术 2025年3月3日
    200
  • 充分发挥异步在 ASP.NET 中的强大优势

    最近几年,异步编程受到极大关注,主要是出于两个关键原因:首先,它有助于提供更好的用户体验,因为不会阻塞 ui 线程,避免了处理结束前出现 ui 界面挂起。其次,它有助于大幅扩展系统,而且无需添加额外硬件。 但是,编写合适的异步代码来管理线程…

    2025年3月3日
    200
  • C# 如何调用 C++ DLL中的函数接口和回调函数

    1、c#中大部分基本数据类型都和c++的基本数据类型相同,因此基本数据类型的转换比较简单,需要注意的就是字节大小。 2、c++数组和c#的数组转换需要注意的就是需要注意,需要增加声明如[marshalas(unmanagedtype.byv…

    编程技术 2025年3月3日
    200
  • c++中向任意目录下写文件

    今天遇到了在c盘的子目录下写文件出错的事情,最中自己实验后解决。小小记录一下。 代码如下: #include#include#include main(){ int data[35]; int n=35,temp; for(int i=0;…

    2025年3月3日
    200
  • C#实现一个最简单的HTTP服务器

     简介   本文用c#实现了一个最简单的http服务器类,你可以将它嵌入到自己的项目中,或者也可以阅读代码来学习关于http协议的知识。  背景   高性能的WEB应用一般都架设在强大的WEB服务器上,例如IIS, Apache, 和Tom…

    编程技术 2025年3月3日
    200
  • 8 种提升 ASP.NET Web API 性能的方法

     asp.net web api 是非常棒的技术。编写 web api 十分容易,以致于很多开发者没有在应用程序结构设计上花时间来获得很好的执行性能。   在本文中,我将介绍8项提高 ASP.NET Web API 性能的技术。  1) 使…

    2025年3月3日
    200
  • ASP.NET Web Forms的改进

    虽然asp.net web forms不是vnext计划的一部分,但它并没有被忽视。作为visual studio 2013 update 2的一部分,它重新开始支持新工具、ef集成和roslyn。   为什么Web Forms不是ASP.…

    2025年3月3日
    200
  • C# 程序员最常犯的 10 个错误

     关于C#   c#是达成微软公共语言运行库(clr)的少数语言中的一种。达成clr的语言可以受益于其带来的特性,如跨语言集成、异常处理、安全性增强、部件组合的简易模型以及调试和分析服务。作为现代的clr语言,c#是应用最为广泛的,其应用场…

    编程技术 2025年3月3日
    200

发表回复

登录后才能评论