2017-07-27 124 views
0

我知道這是一個非常受歡迎的問題,但是我找到的解決方案都不適合我。如何在MouseMove事件期間停止閃爍控制

背景:我有一個VS2015中的窗體項目,它從文本文件中讀取數據,並在折線圖上繪製多個系列的數據。 Chart.MouseMove事件查找最接近鼠標的點並在其周圍繪製一個圓圈。圓圈繪製在Chart_Paint事件

Private Sub crtLogView(sender As Object,e As PaintEventArgs) Handles crtLogView.Paint 
     Dim whitePen as New Pne(Color.White,2) 
     e.Graphics.DrawEllipse(whitePen,cir) '//cir is a Public Rectangle 
End Sub 

當移動跨越圖表鼠標,隨機控制閃爍,然後重新開啓這是很煩人的。我已經發布了下面的MouseMove事件代碼。

潛在的解決方案我曾嘗試:

  • 打開的窗體DoubleBuffered屬性,它什麼都不做
  • 使用Me.Invalidate()和Me.Update()方法,它不動圓
  • 使用Chart.Invalidate()和Chart.Update()方法,它的工作原理,但速度很慢
  • 添加以下代碼,以我的Form_Load例程,它顯得無能爲力

任何幫助,將不勝感激

Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True) 
Me.SetStyle(ControlStyles.DoubleBuffer, True) 
Me.SetStyle(ControlStyles.UserPaint, True) 

MouseMove事件代碼:

Private Sub crtLogView_MouseMove(sender As Object, e As MouseEventArgs) Handles crtLogView.MouseMove 

     '//Show data for closest point to cursor & draw circle around point 
     Dim hResult As HitTestResult = crtLogView.HitTest(e.X, e.Y) 
     Dim srsNam As String = "" 
     Dim mouseY As Single 
     Dim pntDist As Double = 0 
     Dim pntX As Single 
     Dim pntY As Single 
     Dim mouseX As Single 

     On Error GoTo ErrTrap 

     '//Get X-Axis Position as integer 
     mouseX = Int(hResult.ChartArea.AxisX.PixelPositionToValue(e.X)) 
     '// Set time value 
     lblTime.Text = String.Format("{0:n2}", hResult.ChartArea.AxisX.PixelPositionToValue(e.X)/160) 

     '//Get Y-Axis Position 
     mouseY = hResult.ChartArea.AxisY.PixelPositionToValue(e.Y) 

     '//Get distance from mouse to point on Series(0) 
     pntDist = Math.Abs(crtLogView.Series(0).Points(mouseX).YValues(0) - mouseY) 
     srsNam = crtLogView.Series(0).Name '//1st series name 
     '//Find closest series 
     For i As Integer = 1 To crtLogView.Series.Count - 1 
      If Math.Abs(crtLogView.Series(i).Points(mouseX).YValues(0) - mouseY) < pntDist Then 
       pntDist = Math.Abs(crtLogView.Series(i).Points(mouseX).YValues(0) - mouseY) 
       srsNam = crtLogView.Series(i).Name 
      End If 
     Next 

     '//Set Top/Left values for circle 
     pntY = crtLogView.ChartAreas(0).AxisY.ValueToPixelPosition(crtLogView.Series(srsNam).Points(mouseX).YValues(0)) - 4 
     pntX = crtLogView.ChartAreas(0).AxisX.ValueToPixelPosition(Val(mouseX)) - 4 

     '//Move circle to closest point 
     cir.Location = New Point(pntX, pntY) 

     '//Refresh the form to move the circle 

     '//This works, but takes 2+ seconds to take effect 
     'crtLogView.Invalidate() 
     'crtLogView.Update() 

     '//This does not work 
     'Me.Invalidate() 
     'Me.Update() 

     '//This works, but randomly makes other controls flash/flicker 
     Me.Refresh() 
ErrTrap: 
    End Sub 
+0

我不知道你爲什麼使用mousemove事件 - 它會一直在燒。您是否嘗試在鼠標移動時重置計時器,然後在停止時繪製圓圈? – peterG

+0

您可能更適合使用圖表註釋或數據點標籤來代替執行自定義繪畫。如果你需要一個例子,我可以提供一個例子。 – TnTinMn

+0

@peterG感謝您的建議!我沒有試過一個計時器,但現在,它只會使閃爍稍不頻繁 – JerryT

回答

0

在評論,我願意提供使用圖表註解或數據點標籤作爲示例替代自定義在鼠標光標下繪製一個圓點並將其包含在下面的代碼中。但是,我意識到DataPoint標記應該提供OP正在尋找的功能,並且可能是正確的解決方案。因此,該選項也包含在內。

註解是圖表級別的圖形,其中DataPoint標記和DataPoint標記的名稱暗示與單個DataPoint相關聯。因爲它們的大小被指定爲圖表區域維度的百分比,所以可以涉及正確的批註大小。此示例不會嘗試根據當前圖表大小調整註釋大小。

以下代碼示例適用於WinForm。在VS中,向WinForm項目添加一個新類,並用此替換自動生成的代碼。將此窗體設置爲啓動窗體。

Imports System 
Imports System.Drawing 
Imports System.Windows.Forms 
Imports Charting = System.Windows.Forms.DataVisualization.Charting 
Public Class ChartDemo : Inherits Form 
    Const yMultiplyer As Double = 100.0 

    Private rnd As Random 

    Friend WithEvents chart As System.Windows.Forms.DataVisualization.Charting.Chart 
    Friend WithEvents rbAnnotation As System.Windows.Forms.RadioButton 
    Friend WithEvents rbDataLabel As System.Windows.Forms.RadioButton 
    Friend WithEvents rbMarker As System.Windows.Forms.RadioButton 

    Private lastPoint As Charting.DataPoint 
    Private ellispeAnnotation As Charting.EllipseAnnotation 

    Public Sub New() 
     InitializeComponent() 
     rnd = New Random(0) ' use same basis for each run 
     SetupChart() 
    End Sub 

    Private Sub InitializeComponent() 
     Me.chart = New System.Windows.Forms.DataVisualization.Charting.Chart() 
     Me.rbAnnotation = New System.Windows.Forms.RadioButton() 
     Me.rbDataLabel = New System.Windows.Forms.RadioButton() 
     Me.rbMarker = New System.Windows.Forms.RadioButton() 
     CType(Me.chart, System.ComponentModel.ISupportInitialize).BeginInit() 
     Me.SuspendLayout() 

     Me.chart.Anchor = AnchorStyles.Top Or 
            AnchorStyles.Bottom Or 
            AnchorStyles.Left Or 
            AnchorStyles.Right 

     Me.chart.Location = New Point(4, 50) 
     Me.chart.Size = New Size(600, 500) 

     Me.rbAnnotation.AutoSize = True 
     Me.rbAnnotation.Location = New Point(50, 10) 
     Me.rbAnnotation.TabIndex = 1 
     Me.rbAnnotation.Text = "Use Annotation" 
     Me.rbAnnotation.UseVisualStyleBackColor = True 

     Me.rbDataLabel.AutoSize = True 
     Me.rbDataLabel.Location = New Point(200, 10) 
     Me.rbDataLabel.TabIndex = 2 
     Me.rbDataLabel.Text = "Use Data Label" 
     Me.rbDataLabel.UseVisualStyleBackColor = True 

     Me.rbMarker.AutoSize = True 
     Me.rbMarker.Location = New Point(400, 10) 
     Me.rbMarker.TabIndex = 3 
     Me.rbMarker.Text = "Use Data Marker" 
     Me.rbMarker.UseVisualStyleBackColor = True 
     Me.rbMarker.Checked = True 

     Me.AutoScaleDimensions = New SizeF(96.0!, 96.0!) 
     Me.AutoScaleMode = AutoScaleMode.Dpi 
     Me.ClientSize = New Size(610, 555) 
     Me.Controls.AddRange({Me.rbDataLabel, Me.rbAnnotation, Me.rbMarker, Me.chart}) 
     Me.Text = "Charting Demo" 
     CType(Me.chart, System.ComponentModel.ISupportInitialize).EndInit() 
     Me.ResumeLayout(False) 
     Me.PerformLayout() 
    End Sub 

    Private Sub SetupChart() 
     chart.ChartAreas.Clear() 
     chart.Legends.Clear() 
     chart.Series.Clear() 
     chart.Annotations.Clear() 

     Dim area1 As New Charting.ChartArea("Area1") 
     chart.ChartAreas.Add(area1) 

     Dim ser As Charting.Series = chart.Series.Add("Series1") 
     ser.ChartArea = area1.Name 
     ser.ChartType = Charting.SeriesChartType.Line 

     ' define defaults for point DataLabels 
     ser.LabelBorderColor = Color.Red 
     ser.LabelBorderWidth = 1 
     ser.LabelBackColor = Color.WhiteSmoke 
     ser.LabelForeColor = Color.Black 

     ' define defaults for point DataMarkers 
     ser.MarkerSize = 10 
     ser.MarkerBorderWidth = 3 
     ser.MarkerBorderColor = Color.Red 
     ser.MarkerColor = Color.Transparent 

     ' points for demo chart 
     For x As Double = -5.0 To 5.0 
      ser.Points.AddXY(x, rnd.NextDouble * yMultiplyer) 
     Next 

     ellispeAnnotation = CreateEllipseAnnotation() 
     ellispeAnnotation.Visible = False 
     chart.Annotations.Add(ellispeAnnotation) 

    End Sub 

    Private Sub chart_MouseLeave(sender As Object, e As EventArgs) Handles chart.MouseLeave 
     ellispeAnnotation.Visible = False 
     ClearLastPointDataLabel() 
     ClearLastPointMarker() 
    End Sub 

    Private Function CreateEllipseAnnotation() As Charting.EllipseAnnotation 
     Dim ret As New Charting.EllipseAnnotation() 
     ret.ForeColor = Color.Black 
     ret.Font = New Font("Arial", 10) 
     ret.LineWidth = 2 
     ret.Height = 7.5 ' % ChartArea height 
     ret.Width = 15  ' % ChartArea width 
     ret.BackColor = Color.PaleGoldenrod 
     ret.LineDashStyle = Charting.ChartDashStyle.Solid 
     Return ret 
    End Function 

    Private Sub chart_MouseMove(sender As Object, e As MouseEventArgs) Handles chart.MouseMove 
     Dim htr As Charting.HitTestResult = chart.HitTest(e.X, e.Y) 

     If htr.ChartElementType = Charting.ChartElementType.DataPoint Then 
      Dim pt As Charting.DataPoint = DirectCast(htr.Object, Charting.DataPoint) 
      If pt IsNot lastPoint Then 
       SetDataPointLabel(pt) 
       SetDataPointAnnotation(pt) 
       SetDataPointMarker(pt) 
       lastPoint = pt 
      End If 
     End If 
    End Sub 

    Private Sub SetDataPointAnnotation(pt As Charting.DataPoint) 
     If rbAnnotation.Checked Then 
      ellispeAnnotation.AnchorDataPoint = pt 
      ellispeAnnotation.Text = String.Format("{0:N2}, {1:N2}", pt.XValue, pt.YValues(0)) 
      ellispeAnnotation.Visible = True 
     End If 
    End Sub 

    Private Sub SetDataPointLabel(pt As Charting.DataPoint) 
     ClearLastPointDataLabel() 
     If rbDataLabel.Checked Then 
      pt.Label = "#VALX{N2}, #VALY{N2}" ' case sensative, use uppercase for #VALX, #VALY 
      pt.IsValueShownAsLabel = True 
     End If 
    End Sub 

    Private Sub ClearLastPointDataLabel() 
     If lastPoint IsNot Nothing Then 
      lastPoint.Label = String.Empty 
      lastPoint.IsValueShownAsLabel = False 
     End If 
    End Sub 

    Private Sub SetDataPointMarker(pt As Charting.DataPoint) 
     ClearLastPointMarker() 
     If rbMarker.Checked Then pt.MarkerStyle = Charting.MarkerStyle.Circle 
    End Sub 

    Private Sub ClearLastPointMarker() 
     If lastPoint IsNot Nothing Then 
      lastPoint.MarkerStyle = Charting.MarkerStyle.None 
     End If 
    End Sub 

    Private Sub rbAnnotation_CheckedChanged(sender As Object, e As EventArgs) Handles rbAnnotation.CheckedChanged 
     If Not rbAnnotation.Checked Then 
      ellispeAnnotation.Visible = False 
     End If 
    End Sub 

    Private Sub rbDataLabel_CheckedChanged(sender As Object, e As EventArgs) Handles rbDataLabel.CheckedChanged 
     ClearLastPointDataLabel() 
    End Sub 

    Private Sub rbMarker_CheckedChanged(sender As Object, e As EventArgs) Handles rbMarker.CheckedChanged 
     ClearLastPointMarker() 
    End Sub 
End Class