Autor Beitrag
stefanpc81
Hält's aus hier
Beiträge: 14



BeitragVerfasst: So 15.04.18 09:01 
Hallo,
ich lade mehrere Images und zusätzlich mehrere Linien mittels e.Graphics.DrawImage() direkt auf ein Panel. Obwohl ich in der Funktion
ausblenden C#-Quelltext
1:
2:
this.SetStyle(ControlStyles.DoubleBuffer, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

verwende, flackern teilweise die Bilder und insbesondere die Linien-Grafik. Was kann ich noch tun, um dies zu verbessern?
Auf stackoverflow.com/qu...g-in-form-invalidate steht in einem Beitrag was von
"You may need to do all of your drawing to an in memory bitmap first, then paint that bitmap to the form so that it is all drawn on screen at once."
Sollte dies die Lösung sein, so weiß nicht, wie ich das auf mein Projekt anwenden sollte.
Hier mein Code
ausblenden volle Höhe 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:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
        private void Create_PFD_Images(PaintEventArgs e)
        {
            if (L_main_elec || R_main_elec || battery == "on")
            {
                this.SetStyle(ControlStyles.DoubleBuffer, true);
                this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

                Rectangle rect1 = new Rectangle(0024040);
                Rectangle rect2 = new Rectangle(0030180);
                Rectangle rect3 = new Rectangle(0020060);
                Rectangle rect4 = new Rectangle(003530);
                Rectangle rect5 = new Rectangle(005030);

                e.Graphics.DrawImage(Img_PFD_oben, 7010, rect1, GraphicsUnit.Pixel);
                e.Graphics.DrawImage(Img_PFD_rechts, 360110, rect2, GraphicsUnit.Pixel);
                e.Graphics.DrawImage(Img_PFD_L, 30185, rect4, GraphicsUnit.Pixel);
                e.Graphics.DrawImage(Img_PFD_R, 320185, rect5, GraphicsUnit.Pixel);

                if (ADIRU != "off")
                {
                    e.Graphics.DrawImage(Img_PFD_halbkreis, 90340, rect3, GraphicsUnit.Pixel);
                }

                if (ADIRU!="align")
                {
                    //für Linien etc.
                    Pen stift_schwarz = new Pen(Color.Black, 1);
                    Pen stift_weiss = new Pen(Color.White, 1);

                    int y = (gamma * 4) + 100;
                    if (y < 0) { y = 0; }
                    else if (y > 200) { y = 200; }

                    Rectangle rect_ADI = new Rectangle(0, y, 200200);
                    e.Graphics.DrawImage(Img_ADI_hinten, 90100, rect_ADI, GraphicsUnit.Pixel);

                    e.Graphics.DrawLine(stift_schwarz, 102199151199);
                    e.Graphics.DrawLine(stift_schwarz, 102200151200);
                    e.Graphics.DrawLine(stift_schwarz, 150201150217);
                    e.Graphics.DrawLine(stift_schwarz, 151201151217);
                    e.Graphics.DrawLine(stift_schwarz, 189199190199);
                    e.Graphics.DrawLine(stift_schwarz, 189200190200);
                    e.Graphics.DrawLine(stift_schwarz, 231201231217);
                    e.Graphics.DrawLine(stift_schwarz, 232201232217);
                    e.Graphics.DrawLine(stift_schwarz, 231199277199);
                    e.Graphics.DrawLine(stift_schwarz, 231200277200);

                    e.Graphics.DrawLine(stift_weiss, 101198101201);
                    e.Graphics.DrawLine(stift_weiss, 101201149201);
                    e.Graphics.DrawLine(stift_weiss, 149201149218);
                    e.Graphics.DrawLine(stift_weiss, 149218152218);
                    e.Graphics.DrawLine(stift_weiss, 152218152198);
                    e.Graphics.DrawLine(stift_weiss, 101198152198);
                    e.Graphics.DrawLine(stift_weiss, 188198191198);
                    e.Graphics.DrawLine(stift_weiss, 191198191201);
                    e.Graphics.DrawLine(stift_weiss, 188198188201);
                    e.Graphics.DrawLine(stift_weiss, 188201191201);

                    e.Graphics.DrawLine(stift_weiss, 278198278201);
                    e.Graphics.DrawLine(stift_weiss, 278201233201);
                    e.Graphics.DrawLine(stift_weiss, 230198230218);
                    e.Graphics.DrawLine(stift_weiss, 230218233218);
                    e.Graphics.DrawLine(stift_weiss, 233218233201);
                    e.Graphics.DrawLine(stift_weiss, 278198230198);
                }
            }
            else { e.Graphics.Clear(Color.Black); }
}


In einer anderen Funktion, welche jede 1 Sek. im Intervall aufgerufen wird, sthet noch
ausblenden C#-Quelltext
1:
panel_PFD.Invalidate();					

Ob der Aufruf mit
ausblenden C#-Quelltext
1:
panel_PFD.Paint += new PaintEventHandler(this.Paint_PFD_Images);					

in dieser oder in der 0.1 sek-Intervallfunktion steht, ändert nichts am Flackern.
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: So 15.04.18 11:44 
Hallo,

verstehe ich das richtig, daß du entsprechend deines letzten Satzes das Abonnieren der Paint-Methode jedesmal (vor dem Zeichnen) durchführst? Das wäre natürlich falsch, da du dann immer mehr Aufrufe je Ereignis erzeugen würdest (und dementsprechend langsamer und flackernder die Anzeige wäre).
Packe dies in den Konstruktor deiner Klasse (ebenso die SetStyle-Aufrufe)!

PS: Alle lokalen Grafikobjekte (wie Pen, Brush, ...) müssen wieder 'disposed' werden. benutzt daher besser
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
using (Pen stift_schwarz = new Pen(Color.Black, 1))
using (Pen stift_weiss = new Pen(Color.White, 1))
{
  // ...
}

Alternativ kannst du auch die Default-Objekte aus den statischen Klassen Pens und Brushes nutzen:
ausblenden C#-Quelltext
1:
2:
Pen stift_schwarz = Pens.Black;
Pen stift_weiss = Pens.White;

Und noch ein Tipp: Die DrawLine-Parameter würde ich ein Array packen und dann in einer Schleife durchlaufen (bessere Trennung von Code und Daten).

Edit: Mir ist noch etwas aufgefallen. Statt PaintEventArgs als Methodenparameter würde ich direkt Graphics übergeben (du benutzt ja keinen andere Eigenschaft der Klasse und der Code wäre auch um einiges kürzer - und eleganter).
stefanpc81 Threadstarter
Hält's aus hier
Beiträge: 14



BeitragVerfasst: So 15.04.18 15:09 
Momentan befindet sich der ganze Quellcode, den ich gepostet habe, in Forms1.cs, das ist dann wohl falsch? Verstehe ich es richtig, dass ich praktisch den ganzen (1. langen) Code von mir in eine Klasse stecken sollte?
Wenn ja, noch eine Nachfrage: In der Planung verwende ich auch noch zwei andere Panels mit anderen Grafiken, aber im Prinzip genau so. Muss ich dafür eine neue 2. und 3. Klasse bilden? Und wohin dann mit den Pens und Brushes?
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: So 15.04.18 17:03 
Eine Form-Klasse ist auch eine Klasse, also mußt du keine andere Klasse erzeugen.
Und die Klasse hat doch wohl schon einen Konstruktor public Form1()?
stefanpc81 Threadstarter
Hält's aus hier
Beiträge: 14



BeitragVerfasst: So 15.04.18 17:44 
Danke soweit. Was muss ich im Konstruktor mit
ausblenden C#-Quelltext
1:
panel_PFD.Paint += new PaintEventHandler(this.Paint_PFD_Images);					

für "new PaintEventHandler" schreiben? Da habe ich im Netz auf die schnelle keine Antwort gefunden.
Den Code habe ich wie folgt geändert:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
        private void Paint_PFD_Images(object sender, Graphics e)
        {
            Create_PFD_Images(e);
        }

        private void Create_PFD_Images(Graphics e)
{...e.DrawImage...}


Wie soll ich 4 Werte in ein Array schreiben? Oder wie hast du dir das vorgestellt? :gruebel:
Zitat:
Und noch ein Tipp: Die DrawLine-Parameter würde ich ein Array packen und dann in einer Schleife durchlaufen (bessere Trennung von Code und Daten).

Ansatz:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
int[] ADI_object = new int[26];

for (i=0; i<=25; i++)
{
e.DrawLine(stift_schwarz, x1, y1, x2, y2); //???
}
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: So 15.04.18 17:58 
Die Methodensignatur muß natürlich übereinstimmen:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
private void Paint_PFD_Images(object sender, PaintEventArgs e)
{
    Create_PFD_Images(e.Graphics);
}

private void Create_PFD_Images(Graphics g)
{...g.DrawImage...}

Und für das Array entweder alle Werte in ein int-Array (und dann jeweils 4 Werte hintereinander auslesen) oder aber gleich ein Rectangle-Array erzeugen.