Autor Beitrag
c#ler
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 176
Erhaltene Danke: 1

Win7 64Bit
C#, VBA, VS2013 Ultimate
BeitragVerfasst: Fr 20.11.15 11:31 
Hallo Werte Kollegen,
Ich habe folgendes Problem.
Ich möchte fortlaufend grüne oder rote Linien in ein Panel zeichnen, abhängig davon, ob das Ergebnis einer Sensorprüfung 1 oder 0 ist.
Im Prinzip habe ich das schon erledigt und es funktioniert, jedoch ist die Lösung nicht gerade performant/hübsch.
Ich schreibe mir jedes Ergebnis der Sensormessung in ein Array und rufe bei jedem Schreibvorgang in das Array die Funktion Panel.Invalidate auf, damit das PaintEvent des Panels gefeuert wird.
Das PanelPaintEvent zeichnet dann für jeden Wert im Array eine grüne oder rote Linie in das Panel.
Da die Wertanzahl im Array stetig steigt, füllt sich das Panel allmählich.
Dadurch, dass ich aber für das zeichnen der Linie das Panel immer für ungültig erklären muss, muss ich immer wieder alle Linien aus dem Array zeichnen statt einfach eine hinzuzufügen.

Hat jemand eine Idee, wie ich die lines zeichnen kann ohne jedes Mal das ganze Panel für ungültig zu erklären (Invalidate).
Das sieht in der Praxis nämlich blöd aus, wenn das Panel die ganze Zeit beim schreiben flackert.
Die Anwendung soll eine Livedarstellung der Ergebnisse liefern, daher kann ich leider nicht warten, bis das array eine bestimmte größe hat und dann alles schreiben.
Wäre für Hilfe dazu sehr dankbar :)

Hier nochmal die beiden wichtigsten Methoden / Event

Programmiert wird in c# mit dem VS2010 Prof.
Schreiben in das Array und Anstoss des Zeichnens
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
private void DrawLine()
{
   if (panel.InvokeRequired)
   {
      // Ergebnisse abholen
      received = Client.Receive(ref RemoteIpEndPoint);
      result = Encoding.UTF8.GetString(received);
      results.Add(result);
      bufferPanel1 = results.ToArray();
      panel.Invoke(new Action(() =>
         panel.Invalidate()));
   }
}



PaintEvent des Panels
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
private void panel_Auswertung1_Paint(object sender, PaintEventArgs e)
{
   int i1 = 0;
   if (bufferPanel1 != null)
   {
      foreach (int ie in bufferPanel1)
      {
         i1++;
         if (ie == 1)
         {
            Pen Greenpen = new Pen(Color.Green, 5);
            Graphics g = e.Graphics;
            g.DrawLine(Greenpen, 0 + i1, 490 + i1, 0);
         }
         else
         {
            Pen Greenpen = new Pen(Color.Red, 5);
            Graphics g = e.Graphics;
            g.DrawLine(Greenpen, 0 + i1, 490 + i1, 0);
         }
      }
   }
}
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Fr 20.11.15 12:42 
Ich würde erstmal DoubleBuffering am Panel auf dem du zeichnest einschalten und schauen ob das schon reicht.

Z.b. ersetzte das Panel durch dieses

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
public class DoubleBufferedPanel : Panel
{
    public DoubleBufferedPanel () : base()
    {
        this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer, true);
    }
}



DrawLine ist etwas merkwürdig implementiert. Was ist wenn DrawLine nicht aus einem anderen Thread ausgeführt wird? Entweder den if weglassen oder auch den else Zweig implementieren.
Ich bezweifle auch das Invalidate synchronisiert werden muß. Invalidate zeichnet nichts sondern markiert nur zum zeichnen. Zeichnen macht eh der Hauptthread. Gefühlt muß da nicht synchronisiert werden.

Für diesen Beitrag haben gedankt: c#ler
c#ler Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 176
Erhaltene Danke: 1

Win7 64Bit
C#, VBA, VS2013 Ultimate
BeitragVerfasst: Fr 20.11.15 13:39 
Zitat:
DrawLine ist etwas merkwürdig implementiert. Was ist wenn DrawLine nicht aus einem anderen Thread ausgeführt wird? Entweder den if weglassen oder auch den else Zweig implementieren.
Ich bezweifle auch das Invalidate synchronisiert werden muß. Invalidate zeichnet nichts sondern markiert nur zum zeichnen. Zeichnen macht eh der Hauptthread. Gefühlt muß da nicht synchronisiert werden.


Hallo, Danke das ist dem weiteren Programmablauf geschuldet.
Ich habe für den Post ein paar Sachen, die nicht relevant sind entfernt.
Ich habe 3 panels in 3 Groupboxen.
Ich verschiebe beispielsweise das aktuell beschriebene Panel nach dem vollständigen füllen in eine andere Groupbox.
Dadurch wird immer das oberste der 3 Panels gefüllt und danach 1 nach unten verschoben, bis es wieder oben ankommt.
Wie gesagt, danke für den Kommi.

Habe gerade durch weiteres Probieren und logische Verknüpfungen eine Lösung gefunden:
Ich habe das Zeichnen der Linien aus dem Event gezogen und in meine Thread Hauptmethode eingebunden.
So wird alles nacheinander gezeichnet ohne das Control für ungültig zu erklären.
Dadurch spare ich mir das neuzeichnen aller Lines und füge nur noch die neuen Hinzu bis ich meine Arrayrange erreicht habe.
:)
c#ler Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 176
Erhaltene Danke: 1

Win7 64Bit
C#, VBA, VS2013 Ultimate
BeitragVerfasst: Mo 23.11.15 09:48 
Ich habe im direkten Zusammenhang mit dem Thema noch eine Frage:
- Wenn ich drawlines in ein panel zeichne und dann das Parent von dem Panel ändere, werden die Drawlines gelöscht.
Muss ich den letzten Stand der Drawlines nochmal in das Panel nach dem verschieben zeichnen oder gibt es eine Möglichkeit das löschen der Controls im Panel beim 'Umhängen' zu verhindern?
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mo 23.11.15 10:25 
c#ler hat folgendes geschrieben:
Ich habe das Zeichnen der Linien aus dem Event gezogen und in meine Thread Hauptmethode eingebunden.

Du darfst nur im Paint-Ereignis zeichnen!!!
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mo 23.11.15 10:56 
Nebenbei was ist der Sinn hinter dem Panel umhängen?
C#
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Mo 23.11.15 14:52 
Zitat:

Hat jemand eine Idee, wie ich die lines zeichnen kann ohne jedes Mal das ganze Panel für ungültig zu erklären (Invalidate).

Wenn ich dein Vorhaben richtig deute, dann hast du in deinem Panel eine Art Diagramm und sobald neue Werte zur Datenquelle (dein Array) hinzukommen, willst du dein Diagramm "verlängern". Um nicht alles neu zeichnen zu müssen könntest du eine Überladung von Invalidate nehmen, wie z.B.: Invalidate(Rectangle).
In dem Rectangle gibst du dann den Bereich an, der neu gezeichnet werden soll. Wenn dein Panel also immer in eine Richtung arbeitet (z.B. von links nach rechts), dann merkst du dir nach jedem Update die Position des neuesten Wertes im Panel. Beim nächsten Update zeichnest du dann alles ab diesem Punkt. Natürlich musst du dann auch deine Paint-Methode dahingehend verändern, dass auch immer nur der neueste Wert gezeichnet wird, da die anderen ja immer noch vorhanden sind.

Aber wenn du nur Probleme mit flickering hast dann sollte DoubleBuffer eigentlich ausreichen. Das sollte die Performance nicht sonderlich bremsen, zumal alles über 24Hz Refresh Rate keine qualitativ höherweritge Infos anzeigen kann. Wenn du z.B. alle 10ms einen neuen Wert bekommst, dann bringt es dir nichts alle 10ms (-> 100Hz) Invalidate aufzurufen, das erzeugt nur overheat.

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler