c++vcl

Is there really a difference between Image->Picture->Assign(Bitmap) and Image->Picture->Bitmap = Bitmap?


I am struggling to understand if there is really a difference between both statements:

Image->Picture->Bitmap = bitmap;  // bitmap is a TBitmap object
Image->Picture->Assign(bitmap);

The VCL help clearly says about the assignment via =:

Note: When assigning the Bitmap property, TPicture assigns the properties of a another TBitmap object. It does not take ownership of the specified value.

This means that the first statement does NOT copy the bitmap into Image->Picture->Bitmap but just the address of the bitmap is taken over by Image->Picture->Bitmap.

Why is then Image->Picture->Bitmap displaying the picture on the screen correctly even after I deleted the bitmap object?


Solution

  • The two statements are functionally equivalent.

    In this statement:

    Image->Picture->Bitmap = bitmap;
    

    What the documentation does not say, but what actually happens, is the TPicture::Bitmap property setter calls Assign() on the TBitmap returned by the TPicture::Bitmap property getter. IOW, it is identical to calling this:

    Image->Picture->Bitmap->Assign(bitmap);
    

    Where TPersistent::Assign() copies data from one object to another compatible object. In this case, TBitmap overrides Assign() to copy the pixel data from another TBitmap.

    The TPicture::Bitmap property getter ensures the TPicture holds its own TBitmap, creating a new one if it does not already have one, and freeing any previous non-bitmap graphic.

    This is roughly equivalent to doing this:

    if (!dynamic_cast<TBitmap*>(Image->Picture->FGraphic))
    // or:
    // if ((Image->Picture->FGraphic != NULL) &&
    //     (!Image->Picture->FGraphic->InheritsFrom(__classid(TBitmap))))
    {
        TBitmap *newBmp = new TBitmap;
        delete Image->Picture->FGraphic;
        Image->Picture->FGraphic = newBmp;
    }
    static_cast<TBitmap*>(Image->Picture->FGraphic)->Assign(bitmap);
    

    In this statement:

    Image->Picture->Assign(bitmap);
    

    TPicture overrides the Assign() method to create a new TBitmap that is a copy of the passed bitmap and then takes ownership of it, freeing any previous graphic.

    This is roughly equivalent to doing this:

    TBitmap *newBmp = new TBitmap;
    newBmp->Assign(bitmap);
    delete Image->Picture->FGraphic;
    Image->Picture->FGraphic = newBmp;
    

    So, in both cases, the TPicture ends up holding its own TBitmap that has copied the data from the passed bitmap.

    This means that the first statement does NOT copy the bitmap into Image->Picture->Bitmap but just the address of the bitmap is taken over by Image->Picture->Bitmap.

    That is not correct, and counter to the documentation you quoted. Taking just the address would be taking ownership, and that is exactly what the documentation explicitly says does not happen.

    Why is then Image->Picture->Bitmap displaying the picture on the screen correctly even after I deleted the bitmap object?

    Because the TPicture has made its own copy of the pixel data. What you do with the original bitmap afterwards doesn't affect the TPicture at all.