Funktionsplotter
-
Ich weis einfach nicht wie ich ein Flag setzten kann bzw. wie ich das hier anwenden kann. Wie ich schon geschrieben habe, ich programmiere noch nicht so lange mit MFC und insgesamt auch noch nicht so lange. Ich würde mich sehr freuen wenn du mir ein Beispiel für ein Flag geben könntest. Ich habe schon ein bisschen gegoogelt, aber nichts verständliches gefunden.
-
Also ich hab es jetzt endlich geschafft. Das mit den Flags setzen geht ja eigentlich total einfach, ich hatte es halt einfach nicht unter diesem Namen gekannt. Vielen Dank für die guten Tips.
-
Zeichne nur in OnPaint.
Warum?
Ich zeichne immer außerhalb von OnPaint in eine eigene CDC bzw. CImage und kopiere diese dann in OnPaint auf den Anzeigebereich.
Dadurch fallen Mehrfachberechnungen weg wenn die Ansicht oft neu gezeichnet wird. Und bei langsameren PC's verhindet man damit dass die Linien langsam Stück für Stück einzeln auf den Bildschirm gezeichnet werden.Darf ich fragen was ich bei meiner Methode falsch gemacht habe?
Durch CImage ist der Speicher leicht handzuhaben und das Speichern als Bild benötigt nur eine zusätzliche Zeile.
Die Positionen der Punkte und Linien werden nur einmal berechnet und beim Zeichnen/Anzeigen gibt es fast keinen zusätzlichen Rechenaufwand.
Durch Abwürgen des Löschen des Hintergrundes gibt es kein Flickern.
Man kann alles sehr einfach ein einer Klasse verkapseln und hat beim Wiederverwenden fast keinen Aufwand beim Anpassen.
Den einzigen Nachteil den ich sehe, ist der etwas höhere Speicherverbrauch.
-
Bernhard. schrieb:
Zeichne nur in OnPaint.
Darf ich fragen was ich bei meiner Methode falsch gemacht habe?
Damit zeichnest Du in den "realen" DC nur im OnPaint und damit wird der DC valid. Damit entsprichst Du erstmal der Grundforderung, die ich hier mal aufstelle.
Dennoch! Warum sollte ich irgendwo bei irgend einer Aktion in einen fiktiven DC zeichnen, wenn mir OnPaint detailiert sagt, welchen Auschnitt er benötigt. Wenn dieser nicht aktualisiert werden muss, kann ich evtl. die gecachten Daten wiedergeben. Was Du vermutlich damit auch erreichst...
Nochmal: Warum sollte ich den Code, der etwas zeichnet auseinanderreißenund mal hier und mal da in einen DC Zeichnen? Das machst Du vermtulich auch nicht.
Es geht darum, dass man nicht in irgendwelchen Handlern irgendwas auf den Bildschirm DC schreibt. Das ist sowieso weg, wenn der nächste OnPaint kommt...
Also nochmal: Zeichne nur in OnPaint... OK?
-
Ich habe noch ein kleines Problem. Ich zeichne nur in OnPaint. Wenn ich jetzt meinen Graphen etwas langsamer zeichnen lassen möchte (also z.B. mit Sleep(1); ) dann wird so lange der Graph gezeichnet wird nur der Graph selbst gezeichnet und der Rest des Fensters ist nicht sichtbar. Ich denke das ist das Flickern von dem ihr immer sprecht, nur das es bei mir ziemlich lange dauert weil das Zeichnen des Graphen eben ein paar Sekunden dauert. Kann ich irgendwie sagen dass nur der Graph gezeichnet werden soll und der Rest einfach so bleibt wie er ist? Ich hatte es mit OnEraseBkgnd() versucht, aber dann wird das Fenster immer durchsichtig und das dauerhaft, das möchte ich natürlich auch nicht. Irgend jemand eine Idee?
-
Ich habe noch ein kleines Problem. Ich zeichne nur in OnPaint. Wenn ich jetzt meinen Graphen etwas langsamer zeichnen lassen möchte (also z.B. mit Sleep(1); ) dann wird so lange der Graph gezeichnet wird nur der Graph selbst gezeichnet und der Rest des Fensters ist nicht sichtbar.
Sleep finktioniert normalerweise erst ab 10ms und aufwärts.
Wenn man einen niedrigeren Wert eingiebt, wird trotzdem 10ms gewartet.
Wenn das Zeichnen / die Animation länger dauert, würde ich mit Doppelpuffer oder mit einem seperaten "Arbeitsthread" arbeiten.Ich denke das ist das Flickern von dem ihr immer sprecht, nur das es bei mir ziemlich lange dauert weil das Zeichnen des Graphen eben ein paar Sekunden dauert.
Das Flickern ist die Zeitdauer zwischen dem der Anzeigebereich gelöscht und neu gezeichnet wird.
Im Normalfall nimmt man dass als "Blinken" wahr.Kann ich irgendwie sagen dass nur der Graph gezeichnet werden soll und der Rest einfach so bleibt wie er ist?
Schau dir mal http://msdn.microsoft.com/en-us/library/2f3csed3(VS.80).aspx an.
Du kannst aber auch in eine CImage Klasse malen und das Bild dann in ein CStatic Element kopieren.
Dass übernimmt dann die ganze Aktualisierungsarbeit in OnPaint.
(So mache ich dass meißtens)
Dass könnte so ausschaun://MyDlg.cpp bool CMyDlg::ZeichneDasZeug() { CImage cDisplayImg; // Bild neu erstellen // X = 600 Pixel // Y = 550 Pixel // Farbtiefe = 24 Bit if(!cDisplayImg.Create(600,550,24)) { return false; } // DC zum malen holen. CDC* dc = CDC::FromHandle(cDisplayImg.GetDC()); // Pinsel deffinieren CBrush cBrush; // Die Farbe Weiß wählen cBrush.CreateSolidBrush(COLORREF(0xFFFFFF)); CBrush* cOldBrush = dc->SelectObject(&cBrush); // Den DC-Bereich weiß malen, da sonst alles schwarz ist dc->Rectangle(0,0,cDisplayImg.GetWidth(),cDisplayImg.GetHeight()); CPen Pen; Pen.CreatePen(PS_SOLID,1,RGB(0,0,0)); CPen* ptrPen=dc->SelectObject(&Pen); // dc->SetViewportOrg(180,-125); // Hier wird lustig gemalt -> Aufpassen dass nicht außerhalb des // Zeichenbereichs gemalt wird dc->MoveTo(0,200); dc->LineTo(0,300); dc->MoveTo(0,300); dc->LineTo(480,300); int x= 0; int y= 0; for (int j = 0; j < 9; j++) { y = rand() %2; x = j; if(y == 0) { dc->LineTo((x*50),300); dc->LineTo((x*50)+50,300); } else { dc->LineTo(x*50,250); dc->LineTo((x*50)+50,250); } } // Zum Schluss immer Aufräumen dc->SelectObject(&cOldBrush); dc->SelectObject(&cptrPen); // DC der CImage Klasse freigeben, sonst kracht's cDisplayImg.ReleaseDC(); //m_cStatic ist die Variable des Static Anzeigeelement's. // Das Bild wird in das Anzeigeelement kopiert m_cStatic.SetBitmap(cDisplayImg.Detach()); }
Ich hatte es mit OnEraseBkgnd() versucht, aber dann wird das Fenster immer durchsichtig und das dauerhaft, das möchte ich natürlich auch nicht.
Dass funktioniert nur, wenn man über den gesammten Bildbereich malt.
Wenn man OnEraseBkgnd abwürgt um das Flickern/Blinken zu verhindern, muss man sich selbst um das Malen des Hintergrunds kümmern.@Martin Richter
"Live" zu berechnen und zeichnen funktioniert nur, wenn man nicht viel zeichnen muss und man genug Rechnerleistung zur Verfügung hat.Ansonsten ist das Arbeiten mit Doppelpuffer bei denenen man das Bild "vorbereitet" und erst bei Bedarf auf den Bildbereich kopiert die bessere Lösung. Vorallem das Zoomen, Verschieben,... mit einem Doppelpuffer wesentlich einfacher.
Schiebe doch einfach einmal ein Programmfenster über den Anzeigebereich wenn eine Plod-Datei mit >1000 Zeilen angezeigt wird.
Einmal mit Doppelbuffer und einmal mit "Live" Zeichnen.