我试图在绘制形状之前预览和调整形状(就像在Paint中一样)。我遇到的问题是,即使我正在使用双缓冲,也仍然会出现可怕的闪烁,这是对包含临时元素的区域调用Invalidate()
的逻辑结果。
另一个问题是使用此方法预览线会导致图形残留物堆积。
当我停止移动鼠标时,鼠标左键仍然按下时,形状也会消失。
PaintForm.cs
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
namespace MyPaint
{
public partial class PaintForm : Form
{
// Where user clicks the first time.
private Point start = Point.Empty;
// Where user releases the mouse button.
private Point end = Point.Empty;
private DrawingElementType currentElementType = DrawingElementType.Line;
private List<DrawingElement> drawingElements;
// Used for double buffering (aka first drawing on a bitmap then drawing the bitmap onto the control).
private Bitmap bmp;
public PaintForm()
{
InitializeComponent();
drawingElements = new List<DrawingElement>();
bmp = new Bitmap(pbCanvas.Width, pbCanvas.Height, PixelFormat.Format24bppRgb);
Graphics.FromImage(bmp).Clear(Color.White);
}
private void pbCanvas_Paint(object sender, PaintEventArgs e)
{
if (bmp != null)
{
bmp.Dispose();
bmp = null;
}
bmp = new Bitmap(pbCanvas.Width, pbCanvas.Height, PixelFormat.Format24bppRgb);
using (Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.White);
g.SmoothingMode = SmoothingMode.AntiAlias;
foreach (var elem in drawingElements)
{
switch (elem.Type)
{
case DrawingElementType.Line:
g.DrawLine(new Pen(Color.BlueViolet), elem.Start, elem.End);
break;
case DrawingElementType.Rectangle:
g.FillRectangle(Brushes.Black, elem.Container);
break;
case DrawingElementType.Ellipse:
g.FillEllipse(Brushes.Bisque, elem.Container);
break;
default:
break;
}
}
}
e.Graphics.DrawImageUnscaled(bmp, new Point(0, 0));
}
private void pbCanvas_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
start = e.Location;
}
}
private void pbCanvas_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
var temp = new DrawingElement(currentElementType, start, e.Location);
using (Graphics g = pbCanvas.CreateGraphics())
{
switch (currentElementType)
{
case DrawingElementType.Line:
g.DrawLine(new Pen(Color.BlueViolet), temp.Start, temp.End);
break;
case DrawingElementType.Rectangle:
g.FillRectangle(Brushes.Black, temp.Container);
break;
case DrawingElementType.Ellipse:
g.FillEllipse(Brushes.Bisque, temp.Container);
break;
default:
break;
}
}
pbCanvas.Invalidate(temp.Container);
}
}
private void pbCanvas_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
end = e.Location;
var elem = new DrawingElement(currentElementType, start, end);
drawingElements.Add(elem);
// This triggers the paint event and only repaints the region of the new element.
pbCanvas.Invalidate(elem.Container);
}
}
private void btnLine_Click(object sender, EventArgs e)
{
currentElementType = DrawingElementType.Line;
}
private void btnEllipse_Click(object sender, EventArgs e)
{
currentElementType = DrawingElementType.Ellipse;
}
private void btnlRectangle_Click(object sender, EventArgs e)
{
currentElementType = DrawingElementType.Rectangle;
}
}
}
DrawingElement.cs
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyPaint
{
enum DrawingElementType
{
Line,
Rectangle,
Ellipse
}
class DrawingElement
{
public Point Start { get; set; }
public Point End { get; set; }
public DrawingElementType Type { get; }
// Returns the region of the control that contains the element.
public Rectangle Container
{
get
{
int width = Math.Abs(End.X - Start.X);
int height = Math.Abs(End.Y - Start.Y);
return new Rectangle(Math.Min(Start.X, End.X), Math.Min(Start.Y, End.Y), width, height);
}
}
public DrawingElement(DrawingElementType type, Point start, Point end)
{
Type = type;
Start = start;
End = end;
}
}
}
我可能会费劲去寻找解决方法。