防止Alpha彩色笔重叠? [英] Prevent Alpha Color Pen from Overlapping?
问题描述
我有一个简单的荧光笔,它使用 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> 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
子类或简单地
<最后说明:我忽略了简单点击的情况;如果他们应该画画,你必须抓住他们,最好在
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 thePen.Width
or less . SettingLineJoin
is also recommened as well a the twoCaps
..
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屋!