2017-07-27 1 views
0

Ich weiß, dass dies eine ziemlich populäre Frage ist, aber keine der Lösungen, die ich gefunden habe, hat für mich funktioniert.Wie man die Steuerelemente während MouseMove Event flackert Event

Hintergrund: Ich habe ein Windows Forms-Projekt in VS2015, das Daten aus Textdateien liest und die Daten als mehrere Serien in einem Liniendiagramm darstellt. Das Chart.MouseMove-Ereignis findet den Punkt, der der Maus am nächsten ist, und zeichnet einen Kreis darum. Der Kreis wird im Fall Chart_Paint gezogen

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 

Wenn über die Karte die Maus zu bewegen, zufällige Kontrollen flackern, auf das dann wieder sehr ärgerlich ist. Ich habe den folgenden MouseMove-Ereigniscode veröffentlicht.

Mögliche Lösungen Ich habe versucht:

  • Einschalten der DoubleBuffered Eigenschaft des Formulars, die nichts
  • Mit dem Me.Invalidate tut() und Me.Update() -Methode, die nicht bewegt sich der Kreis
  • die Chart.Invalidate Verwendung() und Chart.Update() -Methode, die funktioniert, ist aber sehr langsam
  • den folgenden Code zu meiner Form_Load Routine hinzufügen, die nichts
zu tun erscheint

Jede mögliche Hilfe bei diesem stark

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

Mouseereigniscode würde geschätzt:

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

Ich bin mir nicht sicher, warum Sie das Mousemove-Ereignis dafür verwenden - es wird die ganze Zeit feuern. Haben Sie versucht, einen Timer zurückzusetzen, während sich die Maus bewegt, und dann den Kreis zu zeichnen, wenn er anhält? – peterG

+0

Sie können besser bedient werden, indem Sie eine Diagrammanmerkung oder ein DataPoint-Label anstelle eines benutzerdefinierten Malvorgangs verwenden. Wenn Sie ein Beispiel benötigen, kann ich eins zur Verfügung stellen. – TnTinMn

+0

@peterG Danke für den Vorschlag! Ich hatte keinen Timer ausprobiert, habe aber jetzt und es macht nur das Flackern etwas seltener – JerryT

Antwort

0

In den Kommentaren, bot ich als ein Beispiel der Verwendung eines Diagramms Annotation oder ein Datapoint Etikett zu schaffen Alternative zum benutzerdefinierten Zeichnen eines Kreises um den Punkt unter dem Mauszeiger und das im unten stehenden Code enthalten. Ich erkannte jedoch, dass ein DataPoint-Marker die vom OP gewünschte Funktion bereitstellen sollte und wahrscheinlich die richtige Lösung ist. Daher ist diese Option ebenfalls enthalten.

Anmerkungen sind Graphiken auf Chart-Ebene, da DataPoint Label und DataPoint Marker, wie der Name andeutet, mit den einzelnen DataPoints verknüpft sind. Die richtige Bemaßung von Beschriftungen kann einbezogen werden, da ihre Größe als Prozentsatz der Abmessungen des Diagrammbereichs angegeben wird. In diesem Beispiel wird nicht versucht, die Annotation basierend auf der aktuellen Diagrammgröße zu ändern.

Das folgende Codebeispiel ist für ein WinForm. Fügen Sie in VS eine neue Klasse zu einem WinForm-Projekt hinzu, und ersetzen Sie den automatisch generierten Code dadurch. Legen Sie dieses Formular als Startformular fest.

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 
Verwandte Themen