Im DrawGrid nur bei Änderung Refresh()



  • Guten Morgen,

    ich habe einen kleinen Mapeditor gebaut, der in ein Unsichtbares StringGrid Zahlen rein schreibt. Bei dem Ereignis DrawCell eines gleich großen DrawGrids habe ich abgefragt, welche Zahl in dem entsprechenden Feld des StringGrinds steht und dementsprechend ein Bild in die Zelle gemalt.
    Mein Problem ist, dass wenn ich ein Refresh() des DrawGrids mache, dann flackern die Bilder recht unglücklich. Ich habe zwar die Bilder aus der Resource geladen, aber wenn ich ein ImageList verwende Flackert es auch. Form1->DoubleBuffered = true; hilft auch nicht.
    Das alles passiert, so wie ich vermute, da es einfach zu viel ist, dass andauernd wieder Bilder in das DrawGrid gezeichnet werden.
    Nun dachte ich mir, dass nur bei einer Änderung des StringGrids an der betreffenden Stelle ein Bild gemalt wird und nicht dauernd jedes Bild. Hat jemand von Euch eine Idee, wie man das anstellen könnte?

    Gruß
    Kasimir

    void __fastcall TForm1::mapDrawCell(TObject *Sender, int ACol, int ARow,
          TRect &Rect, TGridDrawState State)
    {
    if(mapx->Cells[ACol][ARow] == 0) {
    	TImage *img_path = new TImage(Form1);
    	img_path->Picture->Bitmap->LoadFromResourceName(int(HInstance), "PATH");
    	map->Canvas->Draw(ACol*32, ARow*32, img_path->Picture->Bitmap);
    }
    if(mapx->Cells[ACol][ARow] == 1) {
    	TImage *img_buildable = new TImage(Form1);
    	img_buildable->Picture->Bitmap->LoadFromResourceName(int(HInstance), "BUILDABLE");
    	map->Canvas->Draw(ACol*32, ARow*32, img_buildable->Picture->Bitmap);
    }
    }
    


  • Warum verwendest du eine Image-Komponente, wenn du nur die Bitmap brauchst?

    Bitmap *bitmap = new TBitmap();
    bitmap->LoadFromResourceName(int(HInstance), "PATH");
    map->Canvas->Draw(ACol*32, ARow*32, bitmap);
    

    Evtl. könntest du die Resourcen ja auch cachen, d.h. nicht immer wieder neu laden.

    Und mit dem unsichtbaren String-Grid machst du es dir auch viel zu umständlich.
    Dafür könntest du dir einfach ein 2-dimensionales Array benutzen (sofern dein Grid konstant groß ist) bzw. ein dynamisches Array. Beim StringGrid werden ja immer wieder Strings verglichen, d.h. intern passiert eigentlich folgendes:

    if(mapx->Cells[ACol][ARow] == AnsiString(0))
    

    Und zum Neuzeichnen nur einzelner Zellen einfach deine DrawCell-Methode selber aufrufen:

    void DrawCell(TDrawGrid *DrawGrid, int ACol, int ARow, TDrawCellEvent DrawCell)
    {
        TRect Rect = DrawGrid->CellRect(ACol, ARow);
    
        if(Rect.Width() > 0) // sichtbar
        {
            TGridDrawState State;
            DrawCell(DrawGrid, ACol, ARow, Rect, State);
        }
    }
    
    //Aufruf dann bei dir:
    int col = ...;
    int row = ...;
    DrawCell(map, col, row, mapDrawCell);
    


  • Anfänglich habe ich auch versucht ein 2-Dimensionales Array zu benutzen, aber ich habe leider wenig Erfahrungen damit wie man mit dem Array arbeitet. Wie es Aufgebaut ist, ist ja relativ simpel, aber wie ich z.B. an die richtige Stelle etwas hinein schreibe wenn es sein muss... Naja, das weiß ich halt nicht.

    Ich habe mal versucht TBitmap zu benutzen, aber bei dem Code den ich probierte und den, den Du geschrieben hast erscheint folgender Fehler:
    [BCC32 Fehler] Unit1.cpp(212): E2015 Mehrdeutigkeit zwischen 'TBitmap' und 'Windows::TBitmap'

    if(mapx->Cells[ACol][ARow] == 1) {
    	TBitmap *img_buildable = new TBitmap();
    	img_buildable->LoadFromResourceName(int(HInstance), "BUILDABLE");
    	map->Canvas->Draw(ACol*32, ARow*32, img_buildable);
    }
    

    Vielleicht habe ich deinen unteren Code nicht ganz verstanden, aber das Verhindert doch nicht, dass andauernd geschrieben wird, oder? TGridDrawState kannte ich bisher noch nicht, aber inwiefern kann ich damit feststellen ob die Zelle gerade geändert wurde und das ich nur dann ein Bild da rein schreibe?
    Sorry, ich steh grad aufm Schlauch 😕

    Vielen Dank für die Hilfe!

    [EDIT]: Selbst wenn es hierfür eine Lösung geben sollte habe ich dennoch mein Grundproblem vom Flackern beim Refresh() gelöst. Ich habe lediglich direkt nacht dem Laden einmal ein Refresh(); ausgeführt und nicht periodisch zur Laufzeit. Das hat zwar das Problem an sich gelöst, aber die Denkanstöße von Dir, Th69, sind ja dennoch nicht außer Acht zu lassen um einen vernünftigen Code zu haben... Also auch wenn ich das Problem gelöst hab bin ich mit dem Weg nicht ganz zufrieden. Könntest Du mir vielleich trotzdem weiter helfen, bei dem was Du vorgeschlagen hast?

    Gruß
    Kasimir



  • Sorry, wegen dem TBitmap - die WinAPI definiert auch einen Typ namens TBitmap, daher muß man immer explizit den Namespace angeben:

    Graphics::TBitmap *pBitmap = new Graphics::TBitmap();
    

    (ich hatte den vorherigen Code aus dem Kopf eingetippt -)

    Mein Code bzgl. DrawCell dient dazu, daß du statt "DrawGrid.Refresh()" gezielt nur einzelne Zellen aktualisierst. Wann du diese Methode aufrufst, mußt du natürlich von außen steuern (d.h. wenn sich der Wert innerhalb des Arrays ändert).

    Unf für ein konstant-großes Array brauchst du doch einfach:

    int myArray[X][Y];
    

    definieren, wobei X und Y halt die festen (bzw. maximalen) Größen (Breite, Höhe) sind.

    Ich selber würde auch noch einige andere (professionellere) Änderungen vornehmen (Bitmap-Array bzw. ImageList), aber alles ersteinmal der Reihe nach...



  • bitmap-array? also ne image-list habe ich schon mal benutzt, auch wenn ich nicht weiß wo da die vorteile sind, gegenüber die datei aus der resource zu laden. um ehrlich zu sein fand ich das sogar komplizierter. aber wie funktioniert denn ein bitmap-array? naja hast recht alles der reihe nach. die anderen sachen werd ich mal probieren. muss doch irgendwie klappen 😉

    Vielen Dank schon mal für die Hilfe!

    Gruß
    Kasimir


Log in to reply