Probleme beim Zeichnen
-
Ich brauche in einer Sache Hilfe, in der ich wirklich am Ende meiner Geduld bin.
Ich habe einen MFC-verwalteten Dialog, dessen OnPaint-Methode so aussieht:
void CAlphaAnalysisDlg::OnPaint() { if (IsIconic()) { /* ... */ } else { data->drawResults(&vidInput); CDialog::OnPaint(); } }Dabei ist vidInput vom Typ CStatic und verwaltet ein Picture Control, in das hineingezeichnet werden soll. data ist ein Pointer auf ein Objekt einer Klasse, die das Zeichnen übernimmt. Die entsprechende Methode drawResults sieht so aus:
void DetectedData::drawResults(CWnd *outputWin) { CPaintDC dc(outputWin); Graphics *graphics = new Graphics(outputWin->GetSafeHwnd()); RECT r; outputWin->GetClientRect(&r); /////// // Das Zeichnen selbst... /////// delete graphics; }Das funzt auch ganz gut, mit einer enorm nervigen und unerklärlichen Ausnahme: Zu einem bestimmten Zeitpunkt passiert es unausweichlich jedes Mal, dass anstatt in das Picture Control stattdessen links oben im Dialog selbst gezeichnet wird, und zwar nicht einmal in der richtigen Größe, sondern in einem anders geformten Rechteck (das aber immer dasselbe ist). Und das verstehe ich überhaupt nicht.
Der ganze Zeichenvorgang wird übrigens aus einer Methode in einem anderen Thread gestart, indem an den Dialog eine WM_PAINT-Nachricht gesendet wird. Ich hatte vermutet, dass vielleicht irgendwie die beiden Threads sich in die Quere kommen, aber das Problem tritt auch auf, wenn der andere Thread eigentlich beendet sein sollte.
Vielleicht weiß ja jemand, wo das Problem ist? Mir ist auch noch aufgefallen, dass es Probleme gibt, wenn ich "Graphics *graphics = new Graphics(dc.m_hDC);" statt der obigen Variante benutze. Ist denn dann vielleicht etwas mit dem Device Context selbst nicht in Ordnung?
-
Du gehst die ganze Sache falsch an, du mußt eine klasse abgeleitet von CStatic erstellen, die du dann an dein Picturectrl bindest (Subclassing), und nur in der klasse wird in OnPiant gezeichnet, nirgendwo anders. Wenn du das neuzeichnen erzwingen willst, dann sende eine UserMessage an die Klasse, welche dann duch Aufruf von InvalidateRect() das Neuzeichnen veranlasst. in der MFC wie in der meisten Frameworks, kannst du net zeichnen wie du willst, sonder nur den Wunsch äußern das du neu zeichnen willst, zeichnen tut immer das Framework.
Hoffe habe das alles Verständlich ausgedrückt
Gruß Matthias
-
Was heißt denn "ich kann nicht zeichen, wie ich will"? Die Nachricht WM_PAINT ist doch genau dazu da, einem Window zu sagen, dass es sich neu zeichnen soll, oder nicht? Oder meinst Du etwa, dass man das Painten nur von "innen" veranlassen kann? Das käme mir nämlich merkwürdig vor. Und wenn ich dann noch definiere, was genau da gezeichnet werden soll, dann muss das doch machbar sein. Da dürfte es doch egal sein, ob ich jetzt in dem Fenster selbst zeichne, oder in einem untergeordneten, auf das ich von oben nach Belieben zugreifen kann.
Ich dachte auch zuerst daran, eine neue Klasse für diese auszufüllende Control zu schreiben, aber weil das Zeichnen selbst auf jeden Fall in der anderen Klasse durchgeführt wird (weil ich da am einfachsten an die Daten komme, die tatsächlich gezeichnet werden sollen), kam mir das zu umständlich vor.
EDIT: Okay, ich habe gerade mitbekommen, dass WM_PAINT nur vom System geschickt werden soll. Welche Nachricht schicke ich denn aber sonst ab, wenn ich etwas mit neuen Daten neu dargestellt haben will?
-
Schau dir mal das Beispiel an, da wirste auch das neuzeichnen finden (m_Icon.Invalidate())in der Funktion void CStaticCtrlTutorialDlg::OnToggleicon() welches das neuzeichnen anschiebt. Das kannst du natürlich auch von Außen über eine UserMessage anschieben. Wobei ich noch nicht Verstanden habe warum du nicht an die zu zeichnenden Daten kommst, brauchst doch nur eine Verbindung zwischen den beiden Klassen zu schaffen, am einfachsten in dem Du einen Zeiger auf die zu Zeichnenden Daten in der UserMessage mit überträgst und nach dem Zeichnen den Speicher wieder frei gibst.
http://www.codeproject.com/KB/static/staticctrl_tut.aspx
Gruß Matthias
-
David Schneider schrieb:
EDIT: Okay, ich habe gerade mitbekommen, dass WM_PAINT nur vom System geschickt werden soll. Welche Nachricht schicke ich denn aber sonst ab, wenn ich etwas mit neuen Daten neu dargestellt haben will?
Keine Nachricht.
InvalidateRect verwenden, dass hat doch CTecS auch schon geschrieben.