2016-05-12 62 views
0

我試圖使用下面列出的PostPaint事件修改動態創建的Chart1對象的圖例中的線條粗細。但是,下面的代碼假定Chart1存在於表單上。有沒有辦法找出Paint Event何時被觸發,然後實現這個PostPaint事件?在圖例中重新創建更好的線條使用PostPaint事件爲動態創建的圖表

Private Sub Chart1_PostPaint(ByVal sender As Object, ByVal e As System.Windows.Forms.DataVisualization.Charting.ChartPaintEventArgs) Handles Chart1.PostPaint 

     If TypeOf e.ChartElement Is Legend Then 

      Dim c As Chart = CType(sender, Chart) 
      Dim g As Graphics = e.ChartGraphics.Graphics 

      'The legend 
      Dim l As Legend = c.Legends(0) 

      'Absolute dimensions of the legend (New legend will be based on this.. won't be exact.) 
      Dim pos As RectangleF = e.ChartGraphics.GetAbsoluteRectangle(l.Position.ToRectangleF) 

      'Absolute dimensions of one legend "cell" 
      Dim itemHeight As Single = pos.Height/c.Series.Count 
      Dim itemWidth As Single = pos.Width/2 

      'Padding between line and text (horizontal) and each item (vertical) 
      Dim horizontalPadding As Single = 10 
      Dim verticalPadding As Single = 1 

      Dim legendFont As New Font("Arial", 10) 

      'Draw a white box on top of the default legend to hide it 
      g.FillRectangle(Brushes.White, pos) 

      For i As Integer = 0 To c.Series.Count - 1 

       Dim s As Series = c.Series(i) 
       Dim p As New Pen(s.Color, CSng(Math.Min(s.BorderWidth, itemHeight))) 'Line no thicker than the item height. 

       'Line 
       Dim posY As Single = CSng(pos.Y + (verticalPadding * i + itemHeight * i + itemHeight/2)) 
       Dim startPoint As PointF = New PointF(pos.X, posY) 
       Dim endPoint As PointF = New PointF(CSng(pos.X + itemWidth), posY) 
       g.DrawLine(p, startPoint, endPoint) 

       'Text 
       posY = CSng(pos.Y + verticalPadding * i + itemHeight * i) 
       startPoint = New PointF(CSng(pos.X + itemWidth), posY) 
       g.DrawString(s.Name, legendFont, Brushes.Black, startPoint.X + horizontalPadding, startPoint.Y) 

      Next 

     End If 

    End Sub 
+0

嘗試過,但因爲是動態創建的圖表手柄Chart1.PostPaint事件拋出異常。這不是一個簡單的按鈕,因此您需要在創建動態創建的Chart時建議如何在代碼中運行代碼。必須有一個解決方法(?) – wrtsvkrfm

回答

0

解決方案,聯想的右對接(見下文底部對接):它的工作,我也有每個系列線ChartDashStyle設置,以及指定一個傳奇的字體和大小。我修改了上面的代碼並調整了相當多的像素調整,以便將新圖例向上移動,並根據圖例的字體大小添加行之間的間距。我還添加了一些邏輯語句將ChartDashStyle轉換爲GDI + DashStyle。

在您動態創建例如Chart1對象,並處理所有代碼來填充系列等,所有你需要做的調用圖表的PostPaint事件是在所有圖表處理代碼末尾添加以下代碼:

Dim Chart1 As New Chart 
Chart1.Invalidate() 
Chart1.ChartAreas.Clear() 
Chart1.Legends.Clear() 
Chart1.Series.Clear() 
. 
. 
(fill series datapoints, legend, titles, etc) 
. 
. 
AddHandler Chart1.PostPaint, AddressOf Chart1_PostPaint 

的繪畫後,PostPaint事件將觸發,然後調用方法(下面的子例程)用彩色線條重新創建圖例,並根據每個系列的相同屬性使用合適的粗細和虛線樣式。

(有不需要是在子程序的定義的端部的Handles...

Private Sub Chart1_PostPaint(ByVal sender As Object, ByVal e As ChartPaintEventArgs) 

     If TypeOf e.ChartElement Is Legend Then 

      Dim c As Chart = CType(sender, Chart) 
      Dim g As Graphics = e.ChartGraphics.Graphics 

      'The legend 
      Dim l As Legend = c.Legends(0) 

      'Absolute dimensions of the legend (New legend will be based on this.. won't be exact.) 
      Dim pos As RectangleF = e.ChartGraphics.GetAbsoluteRectangle(l.Position.ToRectangleF) 

      'Absolute dimensions of one legend "cell" 
      Dim itemHeight As Single = pos.Height/c.Series.Count + 30 
      Dim itemWidth As Single = pos.Width/2 
      'Padding between line and text (horizontal) and each item (vertical) 
      Dim horizontalPadding As Single = 10 
      Dim verticalPadding As Single = l.Font.Size 

      Dim legendFont As Font = l.Font 

      'Draw a white box on top of the default legend to hide it 
      g.FillRectangle(Brushes.White, pos) 

      For i As Integer = 0 To c.Series.Count - 1 
       Dim s As Series = c.Series(i) 
       Dim p As New Pen(s.Color, CSng(Math.Min(s.BorderWidth, itemHeight))) 'Line no thicker than the item height. 
       Dim ds As ChartDashStyle = s.BorderDashStyle 
       'Line 
       Dim posY As Single = CSng(pos.Y + (verticalPadding * i + itemHeight * i + itemHeight/2)) - (c.Series.Count + 2) * verticalPadding 
       Dim startPoint As PointF = New PointF(pos.X, posY) 
       Dim endPoint As PointF = New PointF(CSng(pos.X + itemWidth), posY) 
       p.DashStyle = ds 
       If ds = ChartDashStyle.Solid Then 
        p.DashStyle = DashStyle.Solid 
       End If 
       If ds = ChartDashStyle.Dash Then 
        p.DashStyle = DashStyle.Dash 
       End If 
       If ds = ChartDashStyle.DashDot Then 
        p.DashStyle = DashStyle.DashDot 
       End If 
       If ds = ChartDashStyle.DashDotDot Then 
        p.DashStyle = DashStyle.DashDotDot 
       End If 
       g.DrawLine(p, startPoint, endPoint) 

       'Text 
       posY = CSng(pos.Y + verticalPadding * i + itemHeight * i) - (c.Series.Count + 2) * verticalPadding 
       startPoint = New PointF(CSng(pos.X + itemWidth), posY) 
       g.DrawString(s.Name, legendFont, Brushes.Black, startPoint.X + horizontalPadding + 5, startPoint.Y - 5) 
      Next 
     End If 
    End Sub 

下面是一個例子得到說明:legend

圖例的底部對接,將碼有結果如下:

Private Sub Chart1_PostPaint(ByVal sender As Object, ByVal e As ChartPaintEventArgs) 

    If TypeOf e.ChartElement Is Legend Then 
     Dim c As Chart = CType(sender, Chart) 
     Dim g As Graphics = e.ChartGraphics.Graphics 

     'The legend 
     Dim l As Legend = c.Legends(0) 

     'Absolute dimensions of the legend (New legend will be based on this.. won't be exact.) 
     Dim pos As RectangleF = e.ChartGraphics.GetAbsoluteRectangle(l.Position.ToRectangleF) 
     Dim numrows As Single = Math.Max(Math.Floor(pos.Height/l.Font.Height), 1) 
     'Absolute dimensions of one legend "cell" 
     Dim itemHeight As Single = pos.Height/numrows 
     Dim numcols As Integer 
     If c.Series.Count = 1 Then numcols = 1 
     If c.Series.Count = 2 Then numcols = 2 
     If c.Series.Count = 4 Then numcols = 4 
     If c.Series.Count = 3 OrElse c.Series.Count > 4 Then numcols = 3 
     Dim itemWidth As Single = pos.Width 
     If c.Series.Count = 1 Then itemWidth = pos.Width 
     If c.Series.Count = 2 Then itemWidth = pos.Width/2 
     If c.Series.Count = 4 Then itemWidth = pos.Width/4 
     If c.Series.Count = 3 OrElse c.Series.Count > 4 Then itemWidth = pos.Width/3 
     itemWidth *= 0.9 
     'Padding between line and text (horizontal) and each item (vertical) 
     Dim horizontalPadding As Single = 10 
     Dim verticalPadding As Single = 1 

     Dim legendFont As Font = l.Font 
     'Dim legendFont As New Font("Arial", 10) 

     'Draw a white box on top of the default legend to hide it 
     g.FillRectangle(Brushes.White, pos) 

     For i As Integer = 0 To c.Series.Count - 1 

      Dim s As Series = c.Series(i) 
      Dim p As New Pen(s.Color, CSng(Math.Min(s.BorderWidth, itemHeight))) 'Line no thicker than the item height. 
      Dim ds As ChartDashStyle = s.BorderDashStyle 
      If ds = ChartDashStyle.Solid Then 
       p.DashStyle = DashStyle.Solid 
      End If 
      If ds = ChartDashStyle.Dash Then 
       p.DashStyle = DashStyle.Dash 
      End If 
      If ds = ChartDashStyle.DashDot Then 
       p.DashStyle = DashStyle.DashDot 
      End If 
      If ds = ChartDashStyle.DashDotDot Then 
       p.DashStyle = DashStyle.DashDotDot 
      End If 
      Dim row As Integer 
      If c.Series.Count = 4 Then row = Math.Ceiling((i + 1)/4) 
      If c.Series.Count <> 4 Then row = Math.Ceiling((i + 1)/3) 
      Dim col As Integer 
      If c.Series.Count = 1 Then col = 0 
      If c.Series.Count = 2 Then col = i Mod 2 
      If c.Series.Count = 4 Then col = i Mod 4 
      If c.Series.Count = 3 OrElse c.Series.Count > 4 Then col = i Mod 3 
      'Line 
      Dim posx As Single = CSng((pos.X + (horizontalPadding + itemWidth * (col - 1)) + itemWidth/2)) 
      Dim posY As Single = CSng((pos.Y + (verticalPadding + itemHeight * (row - 1)) + itemHeight/2)) 
      Dim startPoint As PointF = New PointF(posx + itemWidth * 0.75, posY) 
      Dim endPoint As PointF = New PointF(CSng(posx + itemWidth), posY) 
      g.DrawLine(p, startPoint, endPoint) 

      'Text 
      posx = posx + itemWidth 
      startPoint = New PointF(posx, posY - l.Font.Height/2) 
      g.DrawString(s.Name, legendFont, Brushes.Black, startPoint.X + horizontalPadding, startPoint.Y) 
     Next 
    End If 

End Sub 

下面是底部對接時的結果示例使用:

enter image description here