Aussetzer beim Bewegen eines Fadenkreuzes mit der Maus



  • Hallo,

    ich habe die Frage zwar schon im Grafik-Unterforum gestellt, bin dann aber
    an Euch verwiesen worden.

    In eine Grafikausgabe, die mehrere Grafen von Messpunkten darstellt, habe ich
    ein Fadenkreuz, bzw. nur den senkrechten Strich davon, reingesetzt.
    Man kann diese senkrechte Linie mit der gedrückten rechten Maustaste nach
    links/rechts verschieben.

    Die Funktion zum Zeichnen dieser Linie, ein einfaches "GDI::LineTo()", rufe ich
    in "OnMouseMove(..)" bei "(nFlags == MK_RBUTTON)" auf. Bei "OnRButtonUp(..)"
    lasse ich diese Linie am Bildschirm stehen. Um die zuletzt gezeichnete Linie
    wieder zu löschen, habe ich ein Rechteck von 2 Pixel Breite um diese Linie definiert,
    über das ich mit "InvalidateRect(m_hWnd,&m_wCrosshairRect,TRUE)" diese Linie
    wieder lösche. Während der Mausbewegung führe ich fast keine Berechnungen durch,
    um hierdurch keine Verzögerungen zu provozieren.

    Trotzdem ruckelt diese Linie, vor allem bei der Linksbewegung, sehr stark.
    Bei schneller Bewegung ist sie auch mal für mehrere Zentimeter verschwunden.

    Wie bekomme ich es hin, das diese Effekte nicht mehr auftreten?
    Einschlägige Grafikprogramme machen das doch auch. Es muss also gehen!

    Probiert habe ich:
    - Das Zeichnen in die "OnDraw()" zu verschieben --> kein Unterschied aber für mich kompliziertere Logik.
    - Mit MemoryDC arbeiten --> Ich zeichne nur eine Linie, habe kein BMP! Aufwand!

    Noch nicht versucht habe ich: "GDI::Path" statt dem Rechteck für das "InvalidateRect()"

    Vielen Dank für Eure Hilfe

    Helmut


  • Mod

    Arbeite mit einem simplen XOR und ohne einen Invalidate.
    2xXOR und die Linie ist weg.

    Flackern liegt meistens daran, dass zwischen einem Invalidate ein WM_ERASEBKGND ausgelöst wird und der WM_PAINT später kommt.

    Was macht Dein WM_ERASEBKGND? Löscht der was, oder malst Du alles in WM_PAINT?
    Wenn ja liegt hier Dein Hauptproblem.



  • Ich habe die einzelnen Messages nicht überprüft. Weiss also nicht genau, was ausgelöst wird.
    Bei mir existiert nur eine "OnDraw()" Funktion. Und die wird durchlaufen.
    Meine Fadenkreuz-Linie zeichne ich allerdings in den Mouse-Events.

    ... Ja, man hat mir gesagt, dass man eigentlich nur in der "OnDraw()" oder "OnPaint()" zeichnen sollte,
    aber in den Mouse-Events hatte ich es leichter.
    Ich habe es ja auch so probiert, mit gleichem Resultat, nur dass alte Linien
    teilweise (beim Loslassen der Maus) übrig bleiben.

    Die gesamte Grafik scheint vom Betrachten her unverändert.
    Es flackert nur diese Linie.

    Aber hättest Du bitte ein Beispiel für dieses XOR?



  • elmut19 schrieb:

    Ich habe die einzelnen Messages nicht überprüft. Weiss also nicht genau, was ausgelöst wird.
    Bei mir existiert nur eine "OnDraw()" Funktion. Und die wird durchlaufen.
    Meine Fadenkreuz-Linie zeichne ich allerdings in den Mouse-Events.

    Du verwendest MFC. Das Win-API-Forum ist also nicht ganz passend.

    Du hast ja schon richtig angemerkt, das Du eigentlich nur in OnDraw zeichnen solltest.
    Merk dir, wo die Linie ist (im Dokument) und sorg dafür das Ondraw die Linie zeichnet;
    wenn das nicht ohnehin pasiert.

    Um nicht alles neu zeichnen zu müssen, nur weil die Linie verschoben wird, kann man sich
    auch die alte Position merken um sie (z.B. mit XOR) zu löschen.

    Martin hatte bereits vorgeschlagen den Hintergrund NICHT zu löschen. Entweder
    muss man einen transparenten Fensterstyle wählen, oder OnEraseBkgnd überschreiben.

    BOOL MyApp::OnEraseBkgnd(CDC* pDC) 
      {
      return FALSE;
      }
    

    Siehe z.B.:
    http://www.codeguru.com/cpp/controls/controls/article.php/c2297/Flicker-free-drawing-of-any-control.htm



  • Vielen Dank.
    Dannwerd i hnoch ein paar Versu!he starte.
    ei eDocument Klasse hat mein Programm übrices nicht.
    Mal sehn, ob ich diese Woche noch dazu komme
    Ich muss immer wieder anderes Zeug machen.



  • Nun hab ich doch noch eine Lösung gefunden, bei der diese Aussetzer in der
    Linksbewegung nicht mehr vorkommen.

    Zum Zeichnen meiner Linie hab ich allerdings GDI+, mit der Linie als GraficsPath verwendet.
    Alles Andere hab ich belassen, wie es war, also auch das Löschen der alten Linie über ein "Rect" und mit "Invalidate()".
    Auch zeichne ich die Linie weiterhin innerhalb der "OnMouseMove()" und
    Meine Anzeigelogik ist dadurch um ein Vielfaches einfacher. (Ja, nicht ganz Standard konform)

    Grundlage war der Beitrag in http://www.codeproject.com/Articles/3962/Using-GDI-with-MFC-or-native-C-C,
    für die includes und die Initialisierung von GDI+.
    Und der vorherige Hnweis auf GDI::Path

    Und das ist dann meine Linie:

    HDC hDc = cDc.GetSafeHdc();
            Graphics graphics(hDc);
            Pen redPen(Color(255,255,100,50), 1);
            GraphicsPath linePath;
            linePath.AddLine(ptMousePoint.x,sSkala.top,ptMousePoint.x,sSkala.bottom);
            graphics.DrawPath(&redPen, &linePath);
    

    Eine Bemerkung habe ich ich doch noch:
    Entgegen dem Vorschlag in Codeproject habe ich die GDI+ Initialisierung in dem View machen müssen,
    in dem ich die Linie zeichne.
    Als ich es in "InitInstance()" des Hauptprogramms gemacht hatte, lief im Debugger alles super.
    Leider wurde aber im Release die Linie nicht gezeichnet.
    Wie soll das jemand verstehen???

    Grüsse
    Helmut


Anmelden zum Antworten