2016-03-16 35 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

如何用按鈕清除畫線? –