2016-03-16 33 views
0

我有一个简单的荧光笔使用Pen对象。当尺寸非常大时,它会创建奇数条纹,您可以通过定义其开始端盖System.Drawing.Drawing2D.LineCap.Round来修复它,但它会立即重叠并失去其透明度。当您平躺多次时,平顶帽也会失去透明度。防止重叠的Alpha彩色笔?

如何创建不重叠的不透明笔或创建宽度较大的条纹?

private static Color baseColor = Color.Yellow; 
bool Draw; 
Graphics g; 
Point start; 
Point end; 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     g = this.CreateGraphics(); 
     Pen1.Color = Color.FromArgb(128, baseColor); 
     Pen1.Width = 50; 
     Pen1.StartCap = System.Drawing.Drawing2D.LineCap.Flat; //I know it's default, just for clarification's sake 
     Pen1.EndCap = System.Drawing.Drawing2D.LineCap.Flat; //' '''' '' ' ''''''' '''' ''' ''''''''''''' ' '''' 
    } 

    private void Form1_MouseDown(object sender, MouseEventArgs e) 
    { 
     Draw = true; 
     start = e.Location; 
    } 

    private void Form1_MouseUp(object sender, MouseEventArgs e) 
    { 
     Draw = false; 
    } 

    private void Form1_MouseMove(object sender, MouseEventArgs e) 
    { 
     if (Draw == true) 
     { 
      end = e.Location; 
      g.DrawLine(Pen1, start, end); 
      start = end; 
     } 
    } 

它表现得像这样; Highlighter Example

注:是的,我知道.CreateGraphics是不是一个好的绘图方法,它具有独特的目的是无关的问题。

+0

不要单独画线!收集它们并使用DrawLines(PL!)来代替!您可能会遇到问题,因为您在Paint事件中没有正确绘制。看,通常避免基本错误并不是无关紧要的, - ) - 同时看看pen.MiterLimit并尽量保持它的宽度的一半左右! – TaW

+0

你有一个例子代码片段吗?我已经将它转换成了DrawLines [Point [] pts = new Point [2] {start,end};''g.DrawLines(Pen1,pts);'并且设置了'MiterLimit = 50;'I仍然得到相同的结果。 –

+0

是的,你需要收集__all__你的观点,而不仅仅是使uip一行的两个!只有在你解决第一个问题后,斜角限制才会起作用。 – TaW

回答

2

你有两个问题与图形对象:

  • 您可以分别得出各行;这会在公共点重叠的地方产生丑陋的文物。取而代之的是用DrawLines方法一齐画出线条! (注意复数!)

  • 您没有限制Pen.MiterLimit;当线条方向急剧变化时,这会产生难看的尖峰。尽量将其限制在Pen.Width或更少的1/2的范围内。设置LineJoin也是在MouseMove recommened以及一两个Caps ..

收集在你的当前行的点在List<Point> currentPoints并在MouseUpcurrentList收集到List<List<Point>> allPointLists

,那么你可以在Paint事件得出两个..

foreach (List<Point> points in allPointLists) 
     if (points.Count > 1) e.Graphics.DrawLines(Pens.Gold, points.ToArray()); 
    if (currentPoints.Count > 1) e.Graphics.DrawLines(Pens.Gold, currentPoints.ToArray()); 

注意,它会立即支付做是正确的,即绘制一个有效的图形对象和总是依赖在Paint事件上,以确保绘图始终根据需要进行更新!使用control.CreateGraphics几乎总是错的,并会尽快为你去超越单一的非持久性绘图操作很疼..

enter image description here

下面是完整的代码:

List<Point> currentPoints = new List<Point>(); 
List<List<Point>> allPointLists = new List<List<Point>>(); 


private void Form1_MouseDown(object sender, MouseEventArgs e) 
{ 
    currentPoints = new List<Point>(); 
} 

private void Form1_MouseUp(object sender, MouseEventArgs e) 
{ 
    if (currentPoints.Count > 1) 
    { 
     allPointLists.Add(currentPoints.ToList()); 
     currentPoints.Clear(); 
    } 
} 

private void Form1_MouseMove(object sender, MouseEventArgs e) 
{ 
    if (e.Button == System.Windows.Forms.MouseButtons.Left) 
    { 
     currentPoints.Add(e.Location); 
     Invalidate(); 
    } 
} 

这里是Paint事件;请注意,我使用两种不同的Pens作为当前画出的线条和较旧的线条。另外请注意,您可以使用DrawCurve,而不是DrawLines获得更平滑的结果..

另外请注意,我用的是List<T>要灵活WRT元素的数量,而我将其转换为在Draw命令数组..

private void Form1_Paint(object sender, PaintEventArgs e) 
{ 
    Color c1 = Color.FromArgb(66, 77, 88, 222); 
    using (Pen pen = new Pen(c1, 50f)) 
    { 
     pen.MiterLimit = pen.MiterLimit/12; 
     pen.LineJoin = LineJoin.Round; 
     pen.StartCap = LineCap.Round; 
     pen.EndCap = LineCap.Round; 
     foreach (List<Point> points in allPointLists) 
      if (points.Count > 1) e.Graphics.DrawLines(pen, points.ToArray()); 
    } 
    Color c2 = Color.FromArgb(66, 33, 111, 222); 

    using (Pen pen = new Pen(c2, 50f)) 
    { 
     pen.MiterLimit = pen.MiterLimit/4; 
     pen.LineJoin = LineJoin.Round; 
     pen.StartCap = LineCap.Round; 
     pen.EndCap = LineCap.Round; 
     if (currentPoints.Count > 1) e.Graphics.DrawLines(pen, currentPoints.ToArray()); 
    } 
} 

为了防止闪烁不要忘了打开DoubleBufferedForm;或使用DoubleBuffered Panel子类或简单地使用PictureBox

最后说明:我忽略了简单点击的情况;如果他们都应该画你必须赶上他们,大概在if (points.Count > 1)检查最好,最好在正确的位置和正确的尺寸做了FillEllipse ..

更新

List<T>是非常有用我很少使用这些日子。下面是如何利用它来实现一个ClearUndo按钮:在MouseUp代码

private void buttonClear_Click(object sender, EventArgs e) 
{ 
    allPointLists.Clear(); 
    Invalidate(); 
} 

private void buttonUndo_Click(object sender, EventArgs e) 
{ 
    allPointLists.Remove(allPointLists.Last()); 
    Invalidate(); 
} 

注意两个小的修正这需要妥善处理currentPoints列表!结算很明显; ToList()调用正在制作一个拷贝的数据,所以我们不清除我们刚刚添加到列表List的实例!

+0

使用位图永久性图形方法而不是OnPaint创建相同的效果是不可能的?我使用其他方法得到相同的结果,但是当我使用OnPaint时,它可以工作。否则,这是一个很好的方法。 –

+0

当然,你可以绘制一个位图,如果a)你有一个位图和b)你确定的图形。您只能使用currentPoints列表,并在MouseUp中将其绘制到位图中。但你的问题是关于绘制到一个表格!?要使用'Graphics g = Graphics.FromImage(bitmap);'和上述相同的方法绘制位图。请注意,您的原始代码是__non-persistent__! – TaW

+0

如何用按钮清除画线? –