應該有很多人都在尋找這方面的資料,看看下面我做的,或許對你會有所幫助,但願如此。
為了實作橡皮筋技術,我用了兩種方法:
第一種是利用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 < tranNumb; i++)
{
g3.DrawLine(p, tranGroup[i][0], tranGroup[i][1]);
}
//把臨時位圖拷貝到窗體繪圖面
g0.DrawImage(bitmap, 0, 0);
}
private void Form1_Load(object sender, EventArgs e)
{
clr = this.BackColor;//擷取窗體背景色
clr1 = Color.FromArgb(clr.A, 255 - clr.R, 255 - clr.G, 255 - clr.B);//反轉背景色
p = new Pen(clr1, 1);//定義滑鼠左鍵按下并移動時繪制變換所用的筆
//自定義線冒
AdjustableArrowCap cap = new AdjustableArrowCap(3, 3);
cap.WidthScale = 3;
cap.BaseCap = LineCap.Square;
cap.Height = 3;
p.CustomEndCap = cap;
//循環繪制變換組中的變換
for (int i = 0; i < 1000; i++)
{
tranGroup[i] = new Point[2];
}
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
Graphics g2 = CreateGraphics();
//判斷變換數
if (tranNumb >= 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();
}
}
}