Heim > Artikel > Backend-Entwicklung > C# GDI implementiert die Gummibandtechnologie
Es dürfte viele Leute geben, die nach Informationen in diesem Bereich suchen. Ich hoffe, dass es für Sie hilfreich ist.
Um die Gummibandtechnologie zu implementieren, habe ich zwei Methoden verwendet:
Die erste besteht darin, die Methode ControlPaint.DrawReversibleLine (Punktanfang, Punktende, Farbe BackColor) zu verwenden. Das Prinzip: Geben Sie den Startpunkt an Zeichnet eine umkehrbare Linie mit der angegebenen Hintergrundfarbe innerhalb der Start- und Endpunkte. Durch erneutes Zeichnen derselben Linie werden die Ergebnisse dieser Methode umgekehrt. Das Zeichnen von Linien mit dieser Methode ähnelt dem Invertieren eines Bildschirmbereichs, bietet jedoch eine bessere Leistung für einen größeren Farbbereich.
Es ist zu beachten, dass der Startpunkt und der Endpunkt relativ zum Bildschirm sind. Daher verwende ich zum Konvertieren die Methode PointTOScreen (Point p).
Leider hat die gezeichnete Transformation (d. h. ein Liniensegment, in meinem Forschungsgebiet nenne ich das Liniensegment mit einem Liniensegment eine Transformation) beim Ziehen der Maus kein Liniensegment. Um die Transformation zu zeichnen, kann dies nur durch Neuzeichnen erreicht werden, wenn die linke Taste gedrückt wird (wenn Sie nicht möchten, dass die Linie erscheint, kommentieren Sie einfach Invalidate() in der MouseDown()-Methode aus). Da bei Verwendung der DrawReversibleLine()-Methode die Hintergrundfarbe backColor=(a,r,g,b) verwendet wird, kann die Farbe automatisch invertiert werden, und zum Neuzeichnen ist die Hintergrundfarbe reversebackColor=( erforderlich, wenn die linke Taste gedrückt wird. a', r', g', b'), wie erhält man also die umgekehrte Farbe der Hintergrundfarbe? Was ich verwendet habe, ist, die ursprüngliche Hintergrundfarbe r, g, b von 255 zu subtrahieren, während die Transparenz unverändert bleibt, d. h. a'=a;r'=255-r;g'=255-g;b'=255 -b; Dann mit dem durch diese Farbe definierten Pinsel neu malen.
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(); } } }
Die zweite Methode besteht darin, die zu löschende Transformation beim Ziehen der Maus direkt mit der Hintergrundfarbe zu zeichnen und mit dem aktuellen Pinsel eine bestimmte Transformation zu zeichnen. Auf diese Weise erscheinen die beim Ziehen der Maus gezeichneten Transformationslinien.
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 < tranNumb; i++) { g3.DrawLine(curPen, tranGroup[i][0], tranGroup[i][1]); } //把临时位图拷贝到窗体绘图面 g0.DrawImage(bitmap, 0, 0); } private void Form1_Load(object sender, EventArgs e) { curPen = new Pen(Color.Black, 1);//定义一个变换确定并要绘制时所用的画笔 clr = this.BackColor;//获取窗体背景色 p = new Pen(clr, 1);//定义鼠标移动是重画所以的画笔 //自定义线冒 AdjustableArrowCap cap = new AdjustableArrowCap(3, 3); cap.WidthScale = 3; cap.BaseCap = LineCap.Square; cap.Height = 3; curPen.CustomEndCap = cap; 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)//如果不是一段新的折线的开始 { 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 < tranNumb; i++) { g1.DrawLine(curPen, tranGroup[i][0], tranGroup[i][1]); } //存储一个变换的终点,作为下一变换的起点 oldP.X = e.X; oldP.Y = e.Y; } } } private void Form1_FormClosed(object sender, FormClosedEventArgs e) { //释放资源 g3.Dispose(); bitmap.Dispose(); g0.Dispose(); } } }
Beide oben genannten Methoden verwenden die Doppelpuffertechnologie: Erstellen Sie zunächst eine Bitmap-Bitmap mit der gleichen Größe wie der Clientbereich, verwenden Sie dann die Bitmap, um eine temporäre Zeichenoberfläche g3 zu erstellen, und zeichnen Sie dann auf g3 Transformieren Sie und zeichnen Sie die Bitmap nach dem Zeichnen mithilfe der Formularzeichenoberfläche g.
Anti-Aliasing-Technologie: Nur ein Satz g3.SmoothingMode = SmoothingMode.AntiAlias, aber bitte beachten Sie, dass die Anti-Aliasing-Technologie nicht verwendet werden kann, wenn die linke Taste gedrückt und die Maus gezogen wird.