MFC SDI | Per GDI in Bitmap zeichnen?



  • Hallo Bernhard,
    vielen Dank für deine Antwort. Das sieht schon mal vielversprechend aus 👍 . Ich werde versuchen, das morgen mal in mein Programm zu intigrieren und gebe dann Rückmeldung. Für heute ist, nach 6 Std. Programmier- und Schreibarbeit, keine Konzentration mehr verfügbar :D.

    Du könntest eventuell auch mal die Suchfunktion bemühen 😉

    Ja du hast Recht, das hätte ich finden müssen. Bin wahrscheinlich mit den falschen Suchbegriffen an die Sache gegangen.

    Danke nochmal.
    Gruß, André



  • Hallo,
    mit Bernhards Methode funktioniert es. Danke nochmal. Ich hab allerdings noch ein paar Fragen zu der Methode:
    Die Größe meines Fensters soll dynamisch sein. Von daher muss ich nach Erstellung des CChildView-Bereiches, die Größe dieses Bereiches ermitteln und außerdem bei einer Größenänderung des CImage anpassen.
    Wie und an welcher Stelle mache ich das am besten?
    Die Anpassung bei Änderung wahrscheinlich in der OnSize()-Funktion.
    Ich bestimme die Fenstergröße bisher so:

    CRect Rectangle;
    GetClientRect(Rectangle);
    int x=Rectangle.Width();
    int y=Rectangle.Height();
    

    Gibts da nicht eine leichtere Methode?

    Vielen Dank für Eure Mithilfe!
    Gruß, andre0605



  • in OnSize() bekommst du doch schon die neue größe in cx und cy geliefert.



  • Wenn du während der Größenänderung dein Bild mitändern willst, verwende zu OnSize zusätzlich OnSizing.

    Gelegentlich kommt es zu unschönen "Rändern" im Bild wenn man ein anderes Fenster über deine Anzeige hinwegbewegt.
    Desswegen solltest du in OnEraseBkgnd auch die Anzeige malen.

    Also:

    BOOL CMyDlg::OnEraseBkgnd(CDC* pDC)
    {
        // Überprüfen ob die CDC verwendet werden kann 
        if(pDC == NULL)
        {
            return FALSE;
        }
    
        // Überprüfen ob die CImageklasse bereit zum Malen ist
        // Wenn cDisplayImg nicht beim Start des Programms initialisiert wird, den Hintergrund in einer else-Bedingung "reinigen" 
        if(!cDisplayImg.IsNull())
        {
            // Das Bild/die Linien auf den Bildbereich klatschen    
            cDisplayImg.Draw(pDC->GetSafeHdc(),0,0);
        }
    
        // Damit verhindert man das Flickern beim Neuzeichnen
        return TRUE;
    }
    

    Wenn du nicht umbedingt immer ein gestochen scharfes Bild haben mußt, kannst du auch anstatt das Bild bei einer Größenänderng immer neu zu generieren einfach beim Kopieren des Bildes die Größe des Bildes auf den Anzeigebereich "zurechtzoomen".

    Dazu verwendest du am Bessten anstatt cDisplayImg.Draw:

    // Damit wird dass Bild schöner, braucht aber ein wenig mehr Rechnerleistung
    dc.SetStretchBltMode(HALFTONE);
    
    // Das Bild/die Linien auf den Bildbereich klatschen und dabei die Größe anpassen
    StretchBlt(dc.GetSafeHdc(),
    			StartpunktX,
    			StartpunktY,
    			Anzeigebreite,
    			Anzeigehöhe,
    			cDisplayImg.GetDC(),
    			0,
    			0,
    			cDisplayImg.GetWidth(),
    			cDisplayImg.GetHeight(),
    			SRCCOPY);
    

    Wenn das Bild nicht verzerrt werden soll, mußt du StartpunktX, StartpunktY, Anzeigebreite und Anzeigehöhe so anpassen, dass das Seitenverhältnis geich mit dem von cDisplayImg ist. (Dabei das Löschen des Hintergrundes nicht vergessen.)



  • Danke für die ausführlichen Antworten 👍 . Ich programmiere das gerade und melde mich dann wenn es geht.
    Vielen Dank für die kompetente Hilfe in diesem Forum! Echt super!
    Gruß, André



  • Mir ist gerade ein anderes Problem aufgefallen:

    void CChildView::OnSize(UINT nType, int cx, int cy)
    {
    	CWnd ::OnSize(nType, cx, cy);
    	cMapImage.Destroy();
    	cMapImage.Create(cx,cy,24);
    }
    

    Ich kann das CImage Objekt nicht in der OnSize erstellen, da es dann ja bei jeder Größenänderung gelöscht und neu erstellt wird. Ich brauche allerdings den aktuellen Stand zum neuzeichnen. In welcher Funktion erstelle ich am besten das Image-Objekt und zeichne es weiß? Es müsste ja eine Funktion sein, die nur einmal zu Beginn aufgerufen wird. OnCreate und PreCreateWindow gehen nicht, da dort die CChildView Größe noch nicht ermittelt werden kann.
    Jetzt stehe ich etwas auf dem Schlauch 😕 😞



  • na ich würde mal sagen wenn ein neues Bild erstellt werden soll, wie in jedem anderen Programm wenn Neu (New) im Nenü aufgerufen wird? Oder halt wenn Laden (load) im Menü aufgerufen wird, dann erstellen und das bild rein laden.

    Wenn die größe des Bildes verändert wird, was natürlich nichts mit der Anzeige zu tun hat, dann wirst du das bild von einem CImage in das andere Kopieren müssen außer CImage hat eine Methode zur Größenanderung.



  • 🙄 Wieder mal etwas,auf das ich selber kommen müsste. Entschuldigt, wenn meine Fragen etwas doof rüberkommen, aber ich arbeite noch nicht so lange mit MFC.
    Ich habe es jetzt so gelöst, dass ich mir in meiner CChildView eine Funktion initView() geschrieben habe, in der ich das CImage erstelle. Diese Funktion rufe ich dann nach dem Verbinden mit dem Roboter auf.

    Das mit der Größenänderung und OnSize() versuche ich dann morgen. Danke soweit!



  • Ich habe schon wieder eine Frage, die ich alleine nicht lösen kann:
    Ich habe jetzt das CImage Objekt in meiner initView belegt:

    if (!cMapImage.IsNull())
    	cMapImage.Destroy();
    CRect rect;
    GetClientRect(rect);
    cMapImage.Create(rect.Width(),rect.Height(),32);	
    CDC* dc = CDC::FromHandle(cMapImage.GetDC());// DC zum malen holen.    
    CBrush cBrush;// Pinsel deffinieren    
    cBrush.CreateSolidBrush(COLORREF(0xFFFFFF));// Die Farbe Weiß wählen
    dc->SelectObject(&cBrush);    
    dc->Rectangle(0,0,cMapImage.GetWidth(),cMapImage.GetHeight());
    this->Invalidate();
    this->UpdateWindow();
    cMapImage.ReleaseDC();
    return 0;
    

    Nun möchte ich gerne die Mitte des DC Koordinatensystems in die Mitte des CImage legen. Dazu hab ich bereits folgendes versucht:

    dc->SetViewportExt(cMapImage.GetWidth(),cMapImage.GetHeight());
    dc->SetViewportOrg(cMapImage.GetWidth()/2,cMapImage.GetHeight()/2);
    

    Die SetViewport Funkionen beziehen sich allerdings immer auf den CChildView Bereich, was dann zu Folge hat, dass mein CImage geviertelt wird.
    (Siehe Bild).
    Wie kann ich nun den Mittelpunkt setzen? Oder geht das mit dieser Methode gar nicht?
    Viele Grüße, André



  • Tut mir leid dass ich jetzt erst schreibe.
    Aber gestern konnte ich nicht mehr schreiben.

    Ich würde an deiner Stelle mit einer fixen Größe von CImage arbeiten.
    Dass erleichtert die Umrechnung der Daten und man muß das Bild nicht immer wieder neu zeichnen.
    Außerdem ist dann nicht dass Problem dass beim Verkleinern des Bildes Daten verliert.

    Passe einfach die Größe des Bildes mit StretchBlt an die Fenstergröße an.

    Ein kleines Beispiel:

    //OnDraw/OnPaint bzw. OnEraseBkgnd
    
    if (!cMapImage.IsNull())
    {
        // Damit wird dass Bild schöner, braucht aber ein wenig mehr Rechnerleistung
        dc.SetStretchBltMode(HALFTONE);
    
        // Das Bild/die Linien auf den Bildbereich klatschen und dabei die Größe anpassen
        StretchBlt(dc.GetSafeHdc(),
                    0,
                    0,
                    Anzeigebreite,
                    Anzeigehöhe,
                    cMapImage.GetDC(),
                    0,
                    0,
                    cMapImage.GetWidth(),
                    cMapImage.GetHeight(),
                    SRCCOPY);
    
       cMapImage.ReleaseDC();
    }
    
    void CChildView::OnSize(UINT nType, int cx, int cy)
    {
        CWnd ::OnSize(nType, cx, cy);
        Anzeigebreite = cx;
        Anzeigehöhe = cy;
    
        Invalidate();
        UpdateWindow();
    }
    
    // Diese Funktion wird nur beim Starten des Programms -> Ein Ausführen in OnSize,... ist nicht nötig
    void CChildView::InitScreen()
    {
        if (!cMapImage.IsNull())
        {
            cMapImage.Destroy();
        }
    
        cMapImage.Create(500,500,24);   
    
        CDC* dc = CDC::FromHandle(cMapImage.GetDC());// DC zum malen holen.    
        CBrush cBrush;// Pinsel deffinieren    
    
        cBrush.CreateSolidBrush(COLORREF(0x0000FF));// Die Farbe rot wählen
        CBrush* cOldBrush = dc->SelectObject(&cBrush);
    
        dc->Rectangle(0,0,cMapImage.GetWidth(),cMapImage.GetHeight());
    
        // Aufräumen nicht vergessen
        dc->SelectObject(cOldBrush)
    }
    

Anmelden zum Antworten