防止Alpha彩色笔重叠? [英] Prevent Alpha Color Pen from Overlapping?

查看:175
本文介绍了防止Alpha彩色笔重叠?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的荧光笔,它使用 Pen 对象。当尺寸非常大时,它会创建奇数条纹,您可以通过定义其Start& End Cap与 System.Drawing.Drawing2D.LineCap.Round 但它会立即重叠并失去其透明度。如果您自己多次绘制平板,平盖也会失去透明度。



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

  private static Color baseColor = Color.Yellow; 
bool Draw;
图形g;
点开始;
点结束;

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; //我知道它是默认的,仅仅为了澄清而已
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;

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

它的行为如此;



注意:是的,我知道 .CreateGraphics 不是一个好的绘图方法,它有一个与这个问题无关的独特用途。

解决方案

绘图对象有两个问题:


  • 您分别绘制每条线;这会在公共点重叠的地方产生丑陋的文物。用 DrawLines 方法一次性绘制所有的线条! (注意复数!)


  • 您没有限制 Pen.MiterLimit ;当线条方向急剧变化时,这会产生难看的尖峰。尝试将其限制在 Pen.Width 或更少的1/2左右。设置 LineJoin 也被推荐为两个 Caps ..




List< Point>中收集当前行的点。 MouseMove 中的currentPoints 并收集到 MouseUp currentList 转换为列表< List< Point>> allPointLists



然后您可以在 Paint 事件中绘制两者。 b

  foreach(在allPointLists中列出< Point>点)
if(points.Count> 1)e.Graphics.DrawLines (Pens.Gold,points.ToArray());
if(currentPoints.Count> 1)e.Graphics.DrawLines(Pens.Gold,currentPoints.ToArray());

注意 strong> only 与一个有效的图形对象和总是依赖于 Paint 事件来确保绘图始终根据需要进行更新!使用 control.CreateGraphics 几乎总是错误的,只要您超出单个非持久性绘图操作,就会受到伤害。



pre> 列表与LT;点和GT; currentPoints = new List< Point>();
列表<列表< Point>> allPointLists = new List< List< Point>>();

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

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


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




$ b $ p $ Paint 事件;请注意,对于当前绘制的线条和较旧的线条,我使用了两个不同的 Pens 。另外请注意,您可以使用 DrawCurve 而不是 DrawLines 来获得更平滑的结果..



另请注意,我使用 List< T> 对元素数量灵活,并将其转换为<
$ b $ pre $私人无效Form1_Paint(对象发件人,PaintEventArgs e)code> Draw
命令..

<
{
颜色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(在allPointLists中列出< Point>点)
if(points.Count> 1)e.Graphics.DrawLines(pen,points.ToArray());
}
颜色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());




$ b $ p
$ b

为防止闪烁,请不要忘记打开 DoubleBuffered 为你的 Form ;或使用 DoubleBuffered Panel 子类或简单地 PictureBox



<最后说明:我忽略了简单点击的情况;如果他们应该画画,你必须抓住他们,最好在 if(points.Count> 1)检查并且最好做一个 FillEllipse 在正确的位置和正确的尺寸。



更新

List< T> 非常有用,我很少使用数组这些日子。以下是如何使用它来实现清除撤消按钮:

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


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

请注意 MouseUp 代码,它需要正确处理 currentPoints 列表!结算很明显; ToList()调用正在对数据进行复制,所以我们不清除刚刚添加到列表List中的实例!

I have a simple highlighter using a Pen object. When the size is very large, it creates odd stripes which you can fix by defining its Start & End Cap withSystem.Drawing.Drawing2D.LineCap.Round but it instantly overlaps itself and loses its transparency. A flat cap also loses its transparency when you draw over itself multiple times.

How can I create an opaque pen that does not overlap itself or create stripes with a large pen width?

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;
        }
    }

It behaves like this;

Note: Yes, I am aware .CreateGraphics is not a good drawing method, it has a unique purpose that is irrelevant to the question.

解决方案

You have two issues with the drawing objects:

  • You draw each Line separately; this will create ugly artifacts where the common points overlap. Instead draw the lines all in one go with the DrawLines method! (Note the plural!)

  • You did not restrict the Pen.MiterLimit; this creates ugly spikes when the lines directions change sharply. Try to restrict it to around 1/2 of the Pen.Width or less . Setting LineJoin is also recommened as well a the two Caps..

Collect the points of your current line in a List<Point> currentPoints in the MouseMove and collect upon MouseUp the currentList into a List<List<Point>> allPointLists !

then you can draw both in the Paint event..

    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());

Note that it will pay immediately to do it right, i.e. draw only with a valid graphics object and always rely on the Paint event to make sure that the drawing is always updated as needed! Using control.CreateGraphics is almost always wrong and will hurt as soon as you go beyond a single non-persistent drawing operation..

Here is the full code:

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();
    }
}

Here is the Paint event; note that I use two different Pens for the currently drawn lines and the older ones. Also note that you can use DrawCurve instead of DrawLines to get even smoother results..

Also note that I use a List<T> to be flexible wrt the number of elements and that I convert it to an array in the Draw commands..

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());
    }
}

To prevent flicker don't forget to turn on DoubleBuffered for your Form; or use a DoubleBuffered Panel subclass or simply a PictureBox!

Final note: I left out the case of simple clicks; if they are supposed to paint you will have to catch them, probably best in the if (points.Count > 1) check and best do a FillEllipse at the right spot and with the right size..

Update

List<T> is so useful I hardly ever use arrays theses days. Here is how to make use of it to implement a Clear and an Undo button:

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

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

Note two small corrections in the MouseUp code this has required to handle the currentPoints list properly! The clearing is obvious; the ToList() call is making a copy of the data, so we don't clear the instance we have just added to te List of Lists!

这篇关于防止Alpha彩色笔重叠?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆