Problem: CScrollView wird kontinuierlich neu gezeichnet.



  • Hallo zusammen

    Ich habe ein CScrollView welches ich mit Inhalt fülle und zum Schluss setze ich abhängig von der Grösse des Inhalts SetScrollSizes(). Soweit so gut, funktioniert tausend mal einwandfrei.

    ABER

    Bei einer ganz bestimmten Grösse, weiss die MFC nie ob es jetzt Scrollbars braucht oder nicht. Die MFC blendet dann ununterbrochen die horinzontalen und vertikalen Scrollbars ein bzw- aus oder setzt sie neu. Jedenfalls wird das Fenster dauernd neu gezeichnet und mein Programm frisst 100% der Rechenleistung weg. Ich bin sozusagen in einer ewigen Nachrichtenschleife.

    Wie kann ich das verhindern? Das Fenster ein paar Pixel grösser oder kleiner machen würde das Problem in diesem einem Fall beheben. Irgendwann taucht aber das Problem wieder auf, da die ScrollSize dynamisch und nicht statisch ist.

    Irgendwelche Tipps für mich?
    Gruss Specht


  • Mod

    Dann hast Du selbst in OnSize oder einem anderen Handler irgendwas drin, was diese neu Berechnung auslöst.
    Standard ist das nicht...

    Die Berechnung in ScrollView erfolgt gezielt ohne Berücksichtigung von Rollbalken. Wenn diese benötigt werden wird erst der eine, dann der andere eingeblendet.

    Veränderst Du selbst die Größe erneut?
    Verendest Du UpdateBars selber irgendwo?
    Blendest Du slebst irgendwo die Scrollbars aus?

    BTW: Wäre dies ein Grundsatzproblem. liese sich das genau in einem CFormView gezielt nachbauen.



  • Hallo Martin

    Danke für deine Antwort. Ich habe meinen Code nochmals durchgesehen und nirgendwo etwas gefunden was die erneute Berechnung auslösen könnte.

    Habe nun aber ein Demo-Projekt gemacht, das genau dieses Verhalten aufweist. Ich fände es super, wenn du es dir einmal anschauen könntest und dein Kommentar dazu abgeben würdest. Ich schicke dir das Projekt gerne per Mail.

    Als Alternative kann man sich von Assistenten auch ein neues Projekt generieren lassen (MDI) und das Haupt-View anstatt von CView von CScrollView ableiten.

    OnInitinalUpdate einfügen:

    void CScrollbar_ProblemView::OnInitialUpdate()
    {
    	CScrollView::OnInitialUpdate();
    
    	CSize scrollSize;
    	scrollSize.cx = scrollSize.cy = 1000;
    	SetScrollSizes(MM_TEXT, scrollSize);
    
    	// TODO: Add your specialized code here and/or call the base class
    }
    

    Im OnDraw folgendes einfügen:

    void CScrollbar_ProblemView::OnDraw(CDC* pDC)
    {
    	CScrollbar_ProblemDoc* pDoc = GetDocument();
    	ASSERT_VALID(pDoc);
    	if (!pDoc) return;
    
    	// TODO: Code zum Zeichnen der systemeigenen Daten hinzufügen
    	CRect rect(CPoint(10,10), CSize(719,378));
    	pDC->Rectangle(rect);
    
    	pDC->TextOutA(30,30,"Zeichnet sich ständig neu!");
    	pDC->TextOutA(30,50,"SetScrollSize 739 x 408 Pixel (Rechteck plus 10px Rand)");
    	pDC->TextOutA(30,70,"Benötigte Grösse des CChildFrames: 742 x 412 Pixel (andere Werte gehen auch)");
    
    	CRect parentRect;
    	GetParentFrame()->GetClientRect(parentRect);
    
    	CString temp;
    	temp.Format("Aktuelle Grösse des CChildView: %i x %i Pixel", parentRect.Width(), parentRect.Height());
    	pDC->TextOutA(30,90,temp);
    
    	rect.InflateRect(0,0,10,10);
    	SetScrollSizes(MM_TEXT, CSize(rect.right, rect.bottom));
    }
    

    F5 drücken und der Rechner sollte ausgelastet sein!

    Gruss Michael


  • Mod

    Whaaaa....

    Specht schrieb:

    [cpp]
    void CScrollbar_ProblemView::OnDraw(CDC* pDC)
    {
    ...
    	SetScrollSizes(MM_TEXT, CSize(rect.right, rect.bottom));
    }
    }
    

    Das ist ein No-Go! ⚠

    In OnPaint sollte niemals Code ausgeführt werden, der erneut ein Neuzeichnen auslöst. Und schon gar icht Code der die Client Größe manipuliert...
    Du musst die Kalkulation vorher durchführen.



  • OK, in diesem Fall habe ich nun also ein grösseres Problem. Vor allem habe ich keinen Plan wie ich die endgültige Grösse zu Beginn wissen soll. Ev. habe ich einen grundsätzlichen Strukturfehler.

    Es läuft bei mir folgendendermassen ab:

    In OnDraw werden weitere Zeichnungs-Funktionen aufgerufen. Denen wird jeweils der CDC als Pointer mitgegeben und als Rückgabe erhalte ich ein Rechteck von der "beschriebenen" Fläche. Diese Funktionen können nach dem selben Prinzip auch weitere Funktionen aufrufen.

    Am Schluss erhalte ich im OnDraw das alles umspannende Rechteck und setzte damit meine Scrollsize. Diese Grösse kann sich ändern.

    Muss ich jetzt im Vorfeld ein Simulationsdurchgang laufen lassen (ähnlich bei DrawText() die Option DT_CALCRECT)? Wenn ja, wo wird das aufgerufen? Oder macht "man" das sowieso komplett anders?

    Gruss Michael


  • Mod

    Das ist unterschiedlich, aber in Deinen Fall würde ich den Objekten eine Layout Funktion geben und eine Render Funktion.
    Layout skaliert das Objekt und gibt die Größe für einen gegebenen DC. Render gibt das Objekt aus.

    Du musst also Layout nur aufrufen wenn, sich Deine Inhalte ändern. Nach Aufruf des Layout kannst Du SetScrollSizes aufrufen.



  • Hallo Martin

    Danke für deinen Input. Ich werde mir deine Tipps zu Herzen nehmen damit mein Code in Zukunft besser wird. Das auftrennen von der Berechnung und dem eigentlichen Zeichnen spart ja schlussendlich auch wieder Rechenleistung.

    Da das Ganze aber recht umfangreich ist und ich es nicht von Heute auf Morgen ändern kann habe ich halt kurzfristig ein Murx eingebaut. Falls die ermittelte Scrollsize (praktisch) gleich gross ist wie die Fenstergrösse erhöhe ich sie vor dem Setzen noch um ein paar Pixel.

    So läuft das ganze mal und ich kann Übermorgen das ganze in schön machen.

    Gruss Michael


Anmelden zum Antworten