Funktionsplotter
-
Jetzt mal eine konkrete Frage. Ich habe ein Gruppenfeld in meinen Dialog gezogen und von dem möchte ich jetzt über GetWindowRect(); oder GetClientRect(); die Position und Größe abfragen. In der Übung die ich dazu mache steht dass ich dem Gruppenfeld die IDC_FARBE zuordnen soll, das habe ich gemacht. Dann steht drin dass ich eine Client Variable m_farbe hinzufügen soll. Ich dachte also damit ist eine Member Variable gemeint und habe dann zur IDC_FARBE die Member Variable m_farbe hinzugefügt. Als Kategorie kann ich nur Control und als Variablentyp CButton auswählen, was anderes geht nicht. Wenn ich dann in OnInitialUpdate(); der View Klasse folgendes aufrufe
GetDlgItem(IDC_FARBE)->GetClientRect(&m_farbe);
und dann kompiliere bekomme ich immer folgenden Fehler.
"error C2664: 'GetClientRect' : Konvertierung des Parameters 1 von 'class CButton *' in 'struct tagRECT *' nicht moeglich"
Ich verstehe auch was das Problem ist, aber ich kann ja keinen anderen Typ auswählen für die Variable m_farbe. Kann mir wer erklären was ich falsch mache und wie es richtig geht? Ich habe eigentlich alles genau so gemacht wie es in der Übung angegeben ist, aber es funktioniert nicht.
@Dialogfensterzeichner
Wenn ich GetClientRect aufrufe ohne zum Beispiel ein Gruppenfeld zu haben, welchen bereich zum zeichnen gibt er mir denn dann zurück?
-
Hat zu meinem konkreten Problem keiner einen Tip für mich? Ich komm einfach nicht dahinter wie das funktioniert.
-
GetDlgItem(IDC_FARBE)->GetClientRect(&m_farbe);
und dann kompiliere bekomme ich immer folgenden Fehler.
"error C2664: 'GetClientRect' : Konvertierung des Parameters 1 von 'class CButton *' in 'struct tagRECT *' nicht moeglich"
Ich verstehe auch was das Problem ist, aber ich kann ja keinen anderen Typ auswählen für die Variable m_farbe. Kann mir wer erklären was ich falsch mache und wie es richtig geht? Ich habe eigentlich alles genau so gemacht wie es in der Übung angegeben ist, aber es funktioniert nicht.
Probiers doch mal mit einer Variable vom Typ CRect oder RECT.
Dann klappt's auch.Also:
//IDC_FARBE -> ID des Element's dessen Position man wissen will //cFensterpositionen -> Da wird die Position reingeschreiben CRect cFensterpositionen; GetDlgItem(IDC_FARBE)->GetClientRect(&cFensterpositionen);
@Dialogfensterzeichner
Wenn ich GetClientRect aufrufe ohne zum Beispiel ein Gruppenfeld zu haben, welchen bereich zum zeichnen gibt er mir denn dann zurück?Ich hoffe du nimmst auch eine Antwort von mir an
GetClientRect hat nichts mit einem Gruppenfeld oder sonst etwas zu tun.
GetClientRect gibt dir die Positionsdaten ohne Rahmen, Kanten, Titelleiste,... des gewählten Elementes/Fensters zurück.
GetWindowRect git dir die Position des gewählten Elementes/Fensters inclusive Rahmen, Titelleiste,... zurück.
Falls es dir noch nicht bekannt ist: (Fast)Alles was man unter Windows am Bildschirm sieht ist Fenster. -> Daher auch der Name.
Der Desktop ist ein Fenster. Darauf befindet sich die GUI deines Programm's und dass ist auch ein Fenster. Auf deinem Programm sind Buttons, Eingabefelder,... und dass sind auch Fenster. Und so weiter und so fort.Stell dir so ein Fenster einfach mal so wie ein Fenster bei deinem Haus/deiner Wohnung vor.
Dass Fenster besteht aus einem Rahmen, dem Fensterstock, einer Glasscheibe und eventuell noch über einen Rollladen (Titelleiste).
GetWindowRect gibt dir die Außenabmessungen des Fensters zurück. Also der gesammte Teil der aus der Mauer raus schaut. Dass bedeutet die Größe und Position mit Fensterstock und Rollladen.GetClientRact ist der Bereich in dem man theoretisch neue Fenster einsetzen kann also im Beispiel Fenster beim Haus die Größe und Position der Glasscheibe. Der mit GetClientRect ermittelte Bereich gibt dir also den Bereich an, in dem du mit deinen Fingerfarben (CDC) mahlen kannst ohne dich um den Fensterstock, den Fensterrrahmen oder den Rollladen sorgen machen zu müssen.
-
Hallo Bernhard,
vielen Dank für deine tolle Antwort.
Bernhard- schrieb:
Probiers doch mal mit einer Variable vom Typ CRect oder RECT.
Dann klappt's auch.Das klappt! Ich hatte mich einfach irgendwie davon aufhalten lassen dass mir der Klassenassistent einfach nur eine Variable vom Typ CButton anbieten wollte. Ich hatte gar nicht daran gedacht einfach eine Variable selbst zu deklarieren ohne den Assistenten zu benutzen. Das war natürlich blöd von mir.
Bernhard- schrieb:
Falls es dir noch nicht bekannt ist: (Fast)Alles was man unter Windows am Bildschirm sieht ist Fenster. -> Daher auch der Name.
Mir war natürlich schon bekannt das Windows aus lauter Fenstern besteht, aber ich verdränge einfach immer wieder das sogar ein Button ein Fenster sein soll. Deine Erklärung hat mir sehr geholfen, Danke.
In der Aufgabe die ich gemacht habe funktioniert übrigens nur GetWindowRect. Bei GetClientRect hat er mir den Zeichenbereich an einer falsche Stelle ausgegeben.
Also Danke nochmal!
-
Bei GetClientRect hat er mir den Zeichenbereich an einer falsche Stelle ausgegeben
Nö.
Dass hat schon seine Richtigkeit.
Es ist immer eine Frage von wo weg die Positionen gerechnet werden und auf was sich die Maße beziehen.
-
Ja du hast natürlich recht. Ich meinte das es für meine Wünsche an die falsche Stelle gezeichnet wurde. Hätte ich das Koordinatenkreuz an die richtige Stelle verschoben, hätte es so natürlich auch geklappt.
Ich habe noch mal eine Frage zu der OnPaint Methode. Also ich möchte, wenn auf einen Button geklickt wird, die OnPaint Methode aufrufen. Leider wird die Methode aber schon immer vor dem ersten mal klicken einmal ausgeführt. Wie kann ich das verhindern? Ich habe schon versucht die OnPaint erst in der OnButton zu deklarieren, aber dann bekomme ich einen Fehler. Auch habe ich versucht die Funktion einfach im Header zu deklarieren und dann aufzurufen, aber trotzdem wird immer einmal ausgeführt. Was mache ich da falsch? Hier mal ein Teil meines Codes:
void CMyDlg::OnButton() { OnPaint(); Invalidate(); UpdateWindow(); }
void CMyDlg::OnPaint() { CPaintDC dc(this); // device context for painting CPen Pen; Pen.CreatePen(PS_SOLID,1,RGB(0,0,0)); ptrPen=dc.SelectObject(&Pen); dc.SetViewportOrg(180,-125); dc.MoveTo(0,200); dc.LineTo(0,300); dc.MoveTo(0,300); dc.LineTo(480,300); int x[9] = {0}; int y[9]; CString strData[9]; CString strRandData; for (int j = 0; j < 9; j++) { y[j] = rand() %2; x[j] = j; if(y[j] == 0) { dc.LineTo((x[j]*50),300); dc.LineTo((x[j]*50)+50,300); } else { dc.LineTo(x[j]*50,250); dc.LineTo((x[j]*50)+50,250); } } // Kein Aufruf von CDialog::OnPaint() für Zeichnungsnachrichten }
-
Du Windows nicht verstanden. OnPaint wirdimmer automatisch aufgerufen und nicht erst wenn Du irgendwas machst.
Wenn Du nihct willst das gezeichnet wird, bevor irgendwas passiert ist, dann musst Du eben entsprechende Flags setzen und berücksichtigen.
-
OnPaint darfst man nicht direkt aufrufen!
Das machst du indirekt indem du Invalidate(); und UpdateWindow(); aufrufst.
Mit Invalidate sagst du dass der Anzeigebereich deines Programmfensters ncht mehr gültig ist und mit UpdateWindow veranlasst du ein Neuzeichnen -> Indirektes Aufrufen von OnPaint.Versuch's doch mal so:
(Es könnten Fehler enthalten sein, weil ich dass aus dem Gedächtnis geschrieben habe)//stdafx.h #include "afxstr.h" #include "atlimage.h"
//MyDlg.h CImage cDisplayImg;
//MyDlg.cpp void CMyDlg::OnButton() { // Wenn schon ein Bild geladen ist -> Speichern und zerstöhren if(!cDisplayImg.IsNull()) { cDisplayImg.Save(_T("C:\\Bild.png"));// Bild spechern cDisplayImg.Destroy();// Bild zerstöhren } // Bild neu erstellen // X = 600 Pixel // Y = 550 Pixel // Farbtiefe = 24 Bit cDisplayImg.Create(600,550,24); ZeichneDasZeug(); // Anzeigebereich für ungültig erklähren Invalidate(); // Alles neu zeichnen UpdateWindow(); } void CMyDlg::ZeichneDasZeug() { // Überprüfen ob ein Bild erzeugt wurde if(cDisplayImg.IsNull()) { // Akustisch Bescheid geben dass etwas nicht stimmt MessageBeep(MB_ICONERROR); return; } // 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(); } void CMyDlg::OnPaint() { CPaintDC dc(this); // device context for painting // Überprüfen ob die CImageklasse bereit zum Malen ist if(!cDisplayImg.IsNull()) { // Das Bild/die Linien auf den Bildbereich klatschen cDisplayImg.Draw(dc.GetSafeHdc(),0,0); } /////////////////////////////////////////////////////////////////// // Kein Aufruf von CDialog::OnPaint() für Zeichnungsnachrichten // /////////////////////////////////////////////////////////////////// } BOOL CMyDlg::OnEraseBkgnd() { // Damit verhindert man das Flickern beim Neuzeichnen return TRUE; }
-
Hallo Bernhard,
danke auf jeden Fall schonmal für die tolle Antwort. Ich versuche mich da jetzt schon seit ein paar Stunden dran, allerdings ein bisschen anders als du es beschrieben hast. Ich bekomme bei meinem Code aber immer einen Fehler. Hier mal ein paar kurze Ausschnitte meines Codes:
void CRandomDlg::OnButton() { GraphPaint(); Invalidate(); UpdateWindow(); }
void CRandomDlg::OnPaint() { CPaintDC dc(this); // device context for painting // TODO: Code für die Behandlungsroutine für Nachrichten hier einfügen CPen Pen; // Erzeugen eines neuen Stift Pen.CreatePen(PS_SOLID,1,RGB(0,0,0)); // Verbinden Stift und Geraet dc.SelectObject(&Pen); dc.SetTextColor(RGB(140,70,0)); // Koordinatenkreuz zeichnen dc.SetViewportOrg(180,-125); //Ursprung des Koordinatenkreuzes versetzen // x- und y-Achse dc.MoveTo(0,230); dc.LineTo(0,300); dc.MoveTo(0,300); dc.LineTo(930,300); // Hier zeichne ich einfach ein paar Linien die immer da sein sollten // Kein Aufruf von CDialog::OnPaint() für Zeichnungsnachrichten }
void CRandomDlg::GraphPaint() { CPaintDC dc(this); CDC dcgraph; CPen pena; dcgraph.SetViewportOrg(180,-125); pena.CreatePen(PS_SOLID,1,RGB(255,0,0)); dcgraph.SelectObject(&pena); dcgraph.MoveTo(0,300); int x[9] = {0}; int y[9]; CString strData[9]; for (int j = 0; j < 9; j++) { y[j] = rand() %2; x[j] = j; strData[j].Format("%d", y[j]); strRandData += strData[j]; m_strRandomData.SetFocus(); m_strRandomData.SetSel(strRandData.GetLength()); m_strRandomData.ReplaceSel(strRandData, false); if(y[j] == 0) { dcgraph.LineTo((x[j]*3),300); dcgraph.LineTo((x[j]*3)+3,300); } else { dcgraph.LineTo(x[j]*3,250); dcgraph.LineTo((x[j]*3)+3,250); } Sleep(50); } }
Tja, ich dachte so müsste es klappen. Ich möchte auch direkt in meinem Dialog zeichnen. Wenn ich alles in der OnPaint aufrufe klappt es auch. Hier hat er irgendwie ein Problem wenn ich "dcgraph.xxx" aufrufe. Sobald ich das in meinem Code drin habe gibt es einen Assert Fehler wenn ich auf meinen Button klicke. Also das Problem muss ja irgendwie an "CDC dcgraph;" liegen. Hast du da eine Idee was ich falsch mache.
Vielen Dank und viele Grüße
Laura
-
1. CPaintDC darf nur in OnPaint Nachrichten verwendet werden.
2. Dein CDC dcgraph; ist NULL, d.h. es ist kein KOntext erzeugt.
3. Wenn Du tatsächlich außerhalb von OnPaint zeichnen musst, dann solltest Du den entsprechenden DC als Zeiger an die Funktion übergeben, wie CView::OnDraw das tut.Ansonsten finde ich den Konstrukt etwa unsinnig. in OnButton zu zeichnen. Es muss doch genügen einfach einen Invalidate und UpdateWindow auszuführen. Für was bitte vorher der GraphPaint?
-
Ich hab die GraphPaint() grad mal noch ein bisserl abgeändert. Jetzt kommt kein Fehler mehr, aber es wird auch nichts gezeichnet. Hab auch schon versucht per Invalidate() und UpdateWindow() an diversen Stellen das Zeichnen zu veranlassen, aber das hat auch nicht geklappt.
void CRandomDlg::GraphPaint() { CPaintDC dc(this); CPen pena; dc.SetViewportOrg(180,-125); pena.CreatePen(PS_SOLID,1,RGB(255,0,0)); dc.SelectObject(&pena); dc.MoveTo(0,300); int x[9] = {0}; int y[9]; CString strData[9]; for (int j = 0; j < 9; j++) { y[j] = rand() %2; x[j] = j; strData[j].Format("%d", y[j]); strRandData += strData[j]; m_strRandomData.SetFocus(); m_strRandomData.SetSel(strRandData.GetLength()); m_strRandomData.ReplaceSel(strRandData, false); if(y[j] == 0) { dc.LineTo((x[j]*3),300); dc.LineTo((x[j]*3)+3,300); } else { dc.LineTo(x[j]*3,250); dc.LineTo((x[j]*3)+3,250); } Sleep(50); } }
Edit: @Martin Richter: haben gleichzeitig gepostet ich werd mir deine Tips also erstmal anschauen
-
Martin Richter schrieb:
Ansonsten finde ich den Konstrukt etwa unsinnig. in OnButton zu zeichnen. Es muss doch genügen einfach einen Invalidate und UpdateWindow auszuführen. Für was bitte vorher der GraphPaint?
Also wenn ich das Zeichnen komplett in OnDraw erledige, wird der Graph schon immer gezeichnet wenn ich den Dialog aufrufe. Ich möchte allerdings den Dialog aufrufen, in dem mein Button zu sehen ist und das Koordinatenkreuz und dann wenn man den Button betätigt soll der Graph gezeichnet werden und die Daten in ein Editfeld geschrieben werden.
Ich habe mir die OnDraw Methode mal angeschaut, allerdings werde ich nicht so ganz schlau draus, was ich dann beim Aufruf übergeben muss. Also einen Zeiger auf irgendwas, aber auf was? Sorry wenn ich mich blöd anstelle, aber ich programmier noch nicht so lange mit MFC.
Hier noch mal mein neuer Code:
void CRandomDlg::OnButton() { OnDraw(); Invalidate(); UpdateWindow(); } void CRandomDlg::OnDraw(CDC *pDC) { CPen pena; pDC->SetViewportOrg(180,-125); pena.CreatePen(PS_SOLID,1,RGB(255,0,0)); pDC->SelectObject(&pena); pDC->MoveTo(0,300); int x[9] = {0}; int y[9]; CString strData[9]; for (int j = 0; j < 9; j++) { y[j] = rand() %2; x[j] = j; strData[j].Format("%d", y[j]); strRandData += strData[j]; m_strRandomData.SetFocus(); m_strRandomData.SetSel(strRandData.GetLength()); m_strRandomData.ReplaceSel(strRandData, false); if(y[j] == 0) { pDC->LineTo((x[j]*3),300); pDC->LineTo((x[j]*3)+3,300); } else { pDC->LineTo(x[j]*3,250); pDC->LineTo((x[j]*3)+3,250); } Sleep(50); } }
-
Ich hatte es Dir schon einmal geschrieben:
1. Verwende ein Flag.
2. Zeichne nur in OnPaint.
3. Das Flag setzt Du um, wenn der Button geklickt wird und dann führst Du einen Invalidate/UpdateWindow durch.Zu Deinem Code:
Deine Fehler haben gar nichts mit der MFC zu tun!
Wieso schreibst Du eine Funktion OnDraw mit einem Argument CDC* und rufst diese Funktion ohne CDC auf?
Wieso rufst Du überhaupt diese Zeichenfunktion in OnButton auf, wenn Dir schon mehrfach gesagt wurde, dass man nur in OnPaint zeichnet unddass diese Aktion sowieso ungültig wird durch die nächsten Statements?
-
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.