Grafik in Dialog einfügen



  • Verschieben tust Du es einfach, indem Du als Dest-X/Y immer was anderes anbigst und das Zeichnen ungefähr 20 mal in der Sekunde machst (also ca. alle 50 ms ein Invalidate aufrufen).



  • 50 ms ist dann auch schon die Grenze. Dafür einfach einen Timer anlegen und wie gesagt Invalidate() aufrufen. Auch wenn man bei Timern die Möglichkeit hat, 1 ms anzugeben, liegt das Minimum bei ca. 50 ms.



  • mhh, okay.
    AAALSO ich bin leider Anfänger, denn ich habe vorher nur mit ANSI-C gearbeitet. Deswegen brauch ich es "leider" etwas umfangreicher, ich schreibe schreibe als erstens

    CClientDC dc(this); //Gerätekontext erzeugen
    
        CBitmap bitmap; //CBitmap Objekt erstellen und Bitmap
        bitmap.LoadBitmap(IDB_DEINEGRAFIK); //aus der Ressource in dieses laden
    
        BITMAP bm;
        bitmap.GetObject(sizeof(bm), &bm); //Größe des Bitmaps ermitteln
    
        CDC speicherDC; //Speicherkontext erzeugen
        speicherDC.CreateCompatibleDC(&dc);
        CBitmap* pOldBitmap = speicherDC.SelectObject(&bitmap);
    
        RECT rect; //Blitten des Bitmaps
        GetClientRect(&rect);
    
        dc.BitBlt(0, 0, bm.bmWidth, bm.bmHeight,
                  &speicherDC, 0, 0, SRCCOPY);
    
        speicherDC.SelectObject(pOldBitmap);
    

    in die OnInitDialog funktion, natürlich habe ich IDB_DEINEGRAFIK ensprechend meiner Ressource angepasst. Wenn ich nun kompiliere kommt mein Dialog aber ohne grafik, was muss ich noch ändern bzw. hinzufügen?
    Bitte hilft mir, denn ich brauch das für die Schule 😉 Danke



  • Schreib das mal in die OnPaint()-Funktion. In diese Funktion sollten eigentlich fast alle Zeichnungen geschrieben werden.
    Ich glaube, zum Zeitpunkt von OnInitDialog() ist dein Dialog noch nicht erstellt und daher wird das Bild nicht mehr angezeigt.
    Korrigiert mich bitte, wenn ich falsch liege. Interessiert mich auch.

    EDIT: Ok, hatte Recht, muss in die OnPaint() oder später, aber nicht in die OnInitDialog(). Habe ich gerade mal ausprobiert. Habe es bisher immer in OnPaint() gemacht.



  • ahh, danke es hat funktioniert, ihr habt mir sehr geholfen.

    Ich habe jetzt auch ein 2tes Bild eingebaut und ich wollte gerne mal zeigen und fragen ob das so nicht vieleicht schlecht programmiert ist. Vieleicht gibt es ja eine bessere Möglichkeit oder ich habe etwas überflüssig gemacht.
    Hier mein Code:

    //////////////////////////////////////////////
    	/////////////Eigener Code, Anfang/////////////
    	//////////////////////////////////////////////
    
        CClientDC dc(this); //Gerätekontext erzeugen
    
        CBitmap bitmap; //CBitmap Objekt erstellen und Bitmap
        bitmap.LoadBitmap(IDB_BLOCK_ROT); //aus der Ressource in dieses laden
    
        BITMAP bm;
        bitmap.GetObject(sizeof(bm), &bm); //Größe des Bitmaps ermitteln
    
        CDC speicherDC; //Speicherkontext erzeugen
        speicherDC.CreateCompatibleDC(&dc);
        CBitmap* pOldBitmap = speicherDC.SelectObject(&bitmap);
    
        RECT rect; //Blitten des Bitmaps
        GetClientRect(&rect);
    
        dc.BitBlt(0, 0, bm.bmWidth, bm.bmHeight,
                  &speicherDC, 0, 0, SRCCOPY);
    
        speicherDC.SelectObject(pOldBitmap);
    
        //--------------------------------------------
        CClientDC dc2(this); //Gerätekontext erzeugen
    
        CBitmap bitmap2; //CBitmap Objekt erstellen und Bitmap
        bitmap2.LoadBitmap(IDB_BLOCK_BLAU); //aus der Ressource in dieses laden
    
        BITMAP bm2;
        bitmap2.GetObject(sizeof(bm2), &bm2); //Größe des Bitmaps ermitteln
    
        CDC speicherDC2; //Speicherkontext erzeugen
        speicherDC2.CreateCompatibleDC(&dc2);
        CBitmap* pOldBitmap2 = speicherDC2.SelectObject(&bitmap2);
    
        RECT rect2; //Blitten des Bitmaps
        GetClientRect(&rect2);
    
        dc2.BitBlt(3, 3, bm2.bmWidth, bm2.bmHeight,
                  &speicherDC2, 0, 0, SRCCOPY);
    
        speicherDC2.SelectObject(pOldBitmap);
    
    	//////////////////////////////////////////////
    	/////////////Eigener Code, Ende///////////////
    	//////////////////////////////////////////////
    

    Edit:
    Ah ich habe gerade herrausgefunden dass, das mit dem 2ten Bild auch so geht, kann mir einer erklären wieso?

    //////////////////////////////////////////////
    	/////////////Eigener Code, Anfang/////////////
    	//////////////////////////////////////////////
          .
          .        //wie oben
          .
    
        //--------------------------------------------
    		CClientDC dc2(this); //Gerätekontext erzeugen
    
        CBitmap bitmap2; //CBitmap Objekt erstellen und Bitmap
        bitmap2.LoadBitmap(IDB_BLOCK_BLAU); //aus der Ressource in dieses laden
    
        BITMAP bm2;
        bitmap2.GetObject(sizeof(bm2), &bm2); //Größe des Bitmaps ermitteln
    
        CBitmap* pOldBitmap2 = speicherDC.SelectObject(&bitmap2);
    
        RECT rect2; //Blitten des Bitmaps
        GetClientRect(&rect2);
    
        dc2.BitBlt(3, 3, bm2.bmWidth, bm2.bmHeight,
                  &speicherDC, 0, 0, SRCCOPY);
    
    	//////////////////////////////////////////////
    	/////////////Eigener Code, Ende///////////////
    	//////////////////////////////////////////////
    

    Ich habe das mit dem Speicherkontext wegelassen und hier:

    CBitmap* pOldBitmap2 = speicherDC.SelectObject(&bitmap2);
    

    einfach das vom ersten Bild genommen, also "&speicherDC" statt beispielsweise "&speicherDC2".

    Und hier auch:

    dc2.BitBlt(3, 3, bm2.bmWidth, bm2.bmHeight,
                  &speicherDC, 0, 0, SRCCOPY);
    


  • Du brauchst nichtmal ein dc2! Es reicht ein dc und ein SpeicherDC.
    Da du ja erst das erste Bild speicherst und ausgibst und dann erst das andere, kannst du ja nur jeweils ein Objekt benutzen.
    Ich hoffe es ist einiger maßen verständlich.
    Daher würde ich das folgendermaßen sortieren:

    // Initialisierungen
    CClientDC dc(this); //Gerätekontext erzeugen
    
    CDC speicherDC; //Speicherkontext erzeugen
    speicherDC.CreateCompatibleDC(&dc);
    
    CBitmap bitmap, bitmap2; //CBitmap Objekt erstellen und Bitmap
    CBitmap* pOldBitmap;
    BITMAP bm, bm2;
    
    RECT rect;                         
    GetClientRect(&rect);
    
    // Bitmap1 laden und ausgeben
    bitmap.LoadBitmap(IDB_BLOCK_ROT);  //aus der Ressource in dieses laden
    bitmap.GetObject(sizeof(bm), &bm); //Größe des Bitmaps 
    
    pOldBitmap = speicherDC.SelectObject(&bitmap);
    
    dc.BitBlt(0, 0, bm.bmWidth, bm.bmHeight,
             &speicherDC, 0, 0, SRCCOPY);
    
    // Und hier nun Bitmap2 laden und ausgeben
    bitmap2.LoadBitmap(IDB_BLOCK_BLAU); //aus der Ressource in dieses laden
    bitmap2.GetObject(sizeof(bm2), &bm2); //Größe des Bitmaps 
    
    speicherDC.SelectObject(&bitmap2);
    
    dc.BitBlt(3, 3, bm2.bmWidth, bm2.bmHeight,
             &speicherDC, 0, 0, SRCCOPY);
    
    // Speicher aufräumen
    speicherDC.SelectObject(pOldBitmap);
    

    😉



  • Paul_C. schrieb:

    Schreib das mal in die OnPaint()-Funktion. In diese Funktion sollten eigentlich fast alle Zeichnungen geschrieben werden.
    Ich glaube, zum Zeitpunkt von OnInitDialog() ist dein Dialog noch nicht erstellt und daher wird das Bild nicht mehr angezeigt.
    Korrigiert mich bitte, wenn ich falsch liege. Interessiert mich auch.

    in OnInitDialog existiert der dialog soweit ich weiss schon aber wenn du das nicht in die OnPaint() Methode schreibst wird es nicht gezeichnet.
    Bzw wenn du ne etra methode schreiben würdest die dir das Bild zeichnen würde und du sie nicht in der OnPaint() aufrufst wird sie eben nur einmal gezeichnet und sobald der Dialog neu gezeichnet werden muss (verschieben, resize, etc) ist das bild weg.
    Daher alles was permanent da sein soll in der OnPaint() zeichnen lassen bzw die entsprechende Funktion von dort aufrufen.

    So, ich hoffe ich hab nicht gelogen ^^



  • Kannst Recht haben. Vielleicht benötigt man ausserhalb noch die Funktionen BeginPaint() und EndPaint().
    Ich wußte das alles mal besser, ist aber nicht mehr viel hängen geblieben.
    Ich glaube ich teste das mal eben. 😉



  • So getestet: Also BeginPaint() und EndPaint() wird nicht benötigt.
    Habe eben einfach in einer Funktion:

    CDC* dc = GetDC();
    dc->MoveTo(500,150);
    dc->LineTo(500,300);
    Invalidate(false);
    

    geschrieben und es funktioniert. 😉



  • dein Code ist komisch

    CClientDC dc(this); //warum nimmst du GetDC ??
    

    zu GetDC gehört nämlich auch ReleaseDC, ansonsten is das ein ÜBELSTES Speicherleck, wws bei jedem Neuzeichnen größer wird
    Warum Invalidate? Wenn du auf dein Fenster zeichnest, wird das sofort umgesetzt.



  • Ja, ReleaseDC() ist schon richtig. Sollte hier nur ein Beispiel sein.
    Mit Invalidate() bin ich mir gerade nicht so sicher. Hatte es schon erlebt, dass nichts gezeichnet wurde, kann mich aber auch irren.

    Und GetClientDC() wollte er nicht annehmen, daher habe ich GetDC() genommen.
    Habe mich jetzt aber nicht drum gekümmert, warum nicht. 😉



  • hallo,

    ich habe nun ein bitmap zu den ressourcen hinzugefügt. nun weiß ich aber nicht, wie ich das auch in den dialog einfügen kann. geht das mit "picture control"? da kann ich dann aber nicht den typ der grafik angeben.

    wäre toll, wenn mir das nochmal jemand erklären könnte.

    gruß



  • also.. dein bitmab im resorsen heisst z.B bitmabxx
    ein picture control auf dem dialog einlegen und mit dem maus markieren.
    im eigenschaftfenster whält type :bitmab und bild wählt bitmabxx..und ..fertig.



  • Vielen Dank,

    wie einfach. Danke!



  • Ich wollte hier gern noch was zum Anzeigen von zwei Bildern sagen: Man sollte nicht beide Bilder auf den CClienDC blitten. Das mag zwar bei einer simplen Ausgabe funktionieren, wenn man sich jetzt aber denkt, daß das eine Bild ein Hintergrund und das andere ein Sprite ist und man das Sprite über den Bildschirm bewegt, kommt es zu Flackereffekten, weil immer erst der Hintergrund, dann das Sprite, dann wieder der Hintergrund und dann das Sprite gezeichnet wird.

    Stattdessen sollte man Double Buffering verwenden, wobei beide Bilder erst in ein drittes Bild kopiert werden und man dieses dann einmal ausgibt. Dieses Verfahren ist übrigens das, nach dem ich vor Monaten mal hier gefragt habe, und wo irgendwelche Klugscheißer mir ständig mit den Hinweisen Google und die Forumssuche gekommen sind. Oder sie gaben mir irgendwelche WinAPI-Tutorials, die mein Problem überhaupt nicht lösten, da dort selbst nur jeweils ein Bild augegeben wurde. Naja, wie auch immer. Ich werde das ganze jetzt ein für allemal klären. Und besagte Klugscheißer sollen mir doch mal nachweisen, wo diese Beschreibung hier im Forum schonmal aufgetaucht ist, so daß ich sie mit der Suche hätte finden können.

    In OnPaint kommt folgendes:

    CClientDC dc (this);
    CDC dcHintergrund, dcSprite, dcSpeicher;
    CBitmap bmpHintergrund, bmpSprite, bmpSpeicher;
    BITMAP bmH, bmS;
    
    bmpHintergrund.LoadBitmap (IDB_HINTERGRUND);
    bmpHintergrund.GetBitmap (&bmH);
    dcHintergrund.CreateCompatibleDC (&dc);
    dcHintergrund.SelectObject (&bmpHintergrund);
    
    bmpSprite.LoadBitmap (IDB_SPRITE);
    bmpSprite.GetBitmap (&bmS);
    dcSprite.CreateCompatibleDC (&dc);
    dcSprite.SelectObject (&bmpSprite);
    
    bmpSpeicher.CreateComaptibleBitmap (&dc, bmH.bmWidth, bmH.bmHeight);
        //Der Speicher hat hier die gleiche Größe wie der Hintergrund.
    dcSpeicher.CreateCompatibleDC (&dc);
    dcSpeicher.SelectObject (&bmpSpeicher);
    
    dcSpeicher.BitBlt (0, 0, bmH.bmWidth, bmH.bmHeight, &dcHintergrund, 0, 0, SRCCOPY);
    dcSpeicher.BitBlt (m_nX, m_nY, bmS.bmWidth, bmS.bmHeight, &dcSprite, 0, 0, SRCCOPY);
        //m_nX und m_nY müssen vorher als Membervarialen deklariert werden. Sie speichern hier die Position des Sprites.
    dc.BitBlt (0, 0, bmH.bmWidth, bmH.bmHeight, &dcSpeicher, 0, 0, SRCCOPY);
        //Auf das Fenster wird pro Funktionsaufruf nur einmal gezeichnet, was eben das Flackern verhindert.
    

    Alles klar? Erst werden alle Bilder in den Speicher kopiert und dann wird der Speicher auf dem Fenster ausgegeben. So macht man das. Ach ja, und Invalidate braucht man nicht. Man ruft einfach bei jeder Veränderung/Bewegung wieder OnPaint auf. Ich glaube, Invalidate flackert auch, ich bin mir aber nicht sicher.

    Und nun sollen mir diese Quacksalber, die mir damals bloß schlaumeierhafte Sprüche lieferten, doch mal sagen, wo es hier im Forum einen weiteren Beitrag zu eben diesem Thema (Double Buffering mit zwei oder mehr Bildern) gibt! Ihr wart ja der Meinung, daß ich nur genug suchen muß. Na los! Wo hätte ich das finden können?
    P.S.: Ich selbst habe es dann durch Ausprobieren hinbekommen. Google oder Eure Forumssuche haben mir null geholfen.



  • da bin ich wieder, und wieder mit einem Problem...
    ich möchte gerne das bild verschieben, wenn ich dann im Programm die variablen für die Koordinaten ändere, dann wird das bild erst geändert wenn ich das Fenster minimiere und wieder maximiere, oder halt ein Fenster drüber schiebe und wieder runter. Ich weiß halt den befehl nicht, wie ich das Fenster neu zeichnen lasse. ich habe die Bilder in „onPaint“, eingebunden. kann mir jemand erklären wie ich nach dem verschieben der Bilder die Bilder neu zeichnen lasse? thx!

    Edit:
    kann m mir außerdem noch schnell jemand neben bei sagen was
    "number = number >> 1;" macht? also wofür sind die beiden ">>"?



  • JumpLink schrieb:

    kann m mir außerdem noch schnell jemand neben bei sagen was
    "number = number >> 1;" macht? also wofür sind die beiden ">>"?

    Er Dividier "number" durch 2



  • Das stimmt nicht ganz genau, dann damit wird der Inhalt von number um ein bit nach rechts geschoben.

    Entsprechend:

    number << 1

    ein Bit nach links geschoben.

    Was auch mit 2(mal oder durch 4) geht usw.

    Um aber den Sinn zu erklären(ja man kann das auch zum Rechnen benutzen):

    Willst du das 3. und 4. Bit haben, dann geht das so:

    number = (number >> 2) & 0xFF;

    anderes Problem:

    Du mußt das neu Zeichnen Veranlassen. Das macht man so:
    [code]
    CXXX::OnPaint()
    {
    //hier Zeichnen
    }
    CXXX:Verschieben()
    {
    //hier neue Position setzen
    Invalidate(); //Veranlast das neu Zeichnen aufruf von OnPaint
    }
    [quote]
    Gruß Matthias



  • @<<: aber wenn man etwas um ein bit verschiebt, kann es dann nicht zu problemen im speicher führen? Ich habe dieses beispiel in einem programm gesehen, in dem zahlen in binare zahlen umgewandelt werden. kann mir jemand ein beispiel machen? was würde z.B passieren wenn in "number" 255 steht?

    @Zeichnen: okay danke, funktioniert. kann ich auch einstellen das nur ein einzelnes Bild oder ein bestimmter Bereich neu gezeichent wird? denn wenn ich das bild nun verschiebe, flimmert ab und zu das ganze Fenster.



  • *hochzieh*


Anmelden zum Antworten