Problem with TBitmap

How can I create a component derived from TBitmap so that when I drop the component from the palette onto a form:

1. It has a bitmap the same size as the control (not streched).
2. The bitmap is filled in a single color (say clNavy).
3. A (clWhite) rectangle is drawn in the bitmap with size proportional to the bitmap.
4. It wil look EXACTLY the same at runtime as it does at design time.

What I'm looking for is what methods should I use, (Create, ReSize, etc)
and what code should go in the methods.
How do I create the bitmap? When do I create the bitmap? etc etc.
LVL 6
zebadaAsked:
Who is Participating?
 
interConnect With a Mentor Commented:
Regards,
Igor
0
 
interCommented:
Hi,
Normally, you would not derive a component from TBitmap. For me the starting point could derive a component from TImage or TPictureBox depending on the capabilities you want. Please elaborate more...

regards, igor
0
 
zebadaAuthor Commented:
Sorry, I made a type, it should have been:

How can I create a component derived from TImage so that when I drop the component from the palette onto a form:


0
Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

 
interCommented:
Basically,

declare

unit ImageX;

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls,
  StdCtrls, Extctrls;

type
  TImageX = class(TImage)
    constructor Create(AOwner: TComponent); override;
  protected
    procedure WMSize(var Message: TWMSize);message WM_SIZE;
    procedure UpdateBitmap;
  public
  end;

procedure Register;

implementation

constructor TImageX.Create(AOwner:TComponent);
begin
  inherited;
  UpdateBitmap;
end;

procedure TImageX.UpdateBitmap;
var
  T : TBitmap;
begin
  T := TBitmap.Create;
  T.Canvas.Brush.Color := clAqua;
  T.Width := ClientWidth;
  T.Height := ClientHeight;
  Picture.Assign(T);
end;

procedure TImageX.WMSize(var Message: TWMSize);
begin
  inherited;
  UpdateBitmap;
end;

procedure Register;
begin
  RegisterComponents('Samples', [TImageXt]);
end;

end.
0
 
zebadaAuthor Commented:
Thanks, that seems to work exactly as I wanted.

One question: UpdateBitmap will be called multiple times, I assume something is taking care of Freeing the Created bitmap. How is it Freed and who is responsible for Freeing it?

Does Picture.Assign free any previously allocated bitmap?

Answer for the points :)
0
 
interCommented:
The pictures assign method takes care of the old graphic whether it contains icon, bitmap or methafile.

What version of Delphi (standart, profetional....etc). If you have prof and up, you may see the source yourself. For example TBitmap, TIcon and TMetaFile are in Graphics.pas at \Source\Vcl\ where as TImage is in extctrls.pas

by the way, 200 points are more for this question, could you be able to lower it? or ask new question with same text and I past the code above...

c.u.
regards, igor
0
 
LischkeCommented:
Igor, your last comment shows you are a gentlement, but consider this: Although the answer might be very easy for you it may not be for the questioneer. Additionally, the points show how important the answer is for the questioneer and raising the same question again just for less points (one cannot lower the points in an already asked question) is too much effort. So, be happy with what you get and be the more helpful the next time zebada asks a question :-))

One comment to your solution, though. The bitmap in UpdateBitmap is NOT automatically freed. The Assign method will only take the properties of the provided bitmap and assign them to its internal bitmap. Hence you need to free the helper bitmap explicitly. An easier solution would be:

procedure TImageX.UpdateBitmap;
begin
  Picture.Bitmap.Width := Width;
  Picture.Bitmap.Height := Height;
end;

Ciao, Mike
0
 
LischkeCommented:
Oops, of course it should be: "gentleman" :-)
0
 
interCommented:
thanks for the compliment. Lets look at some core VCL:

procedure TBitmap.Assign(Source: TPersistent);
var
  DIB: TDIBSection;
begin
  if (Source = nil) or (Source is TBitmap) then
  begin
    EnterCriticalSection(BitmapImageLock);
    try
      if Source <> nil then
      begin
        // bitmap references the source bitmap saying the
        // the image manager should know it has the bitmap
        TBitmap(Source).FImage.Reference;
        // Note that self image is released. if this makes
        // refrence count of the memory image = 0 the
        // bitmap is released by the image manager
        FImage.Release;
        FImage := TBitmap(Source).FImage;
        FTransparent := TBitmap(Source).FTransparent;
        FTransparentColor := TBitmap(Source).FTransparentColor;
        FTransparentMode := TBitmap(Source).FTransparentMode;
      end
      else
      begin
        FillChar(DIB, Sizeof(DIB), 0);
        NewImage(0, 0, DIB, False);
      end;
    finally
      LeaveCriticalSection(BitmapImageLock);
    end;
    PaletteModified := Palette <> 0;
    Changed(Self);
  end
  else inherited Assign(Source);
end;


what is your evaluation on this code (the comments are mine not from the borland team-so it may not be correct-)

regards, igor
0
 
interCommented:
I admit your pointer is better though.
0
 
LischkeCommented:
For a moment I was a bit irritated by what you could mean, but after carefully reading the comments above I realized we where talking different lines.

Of course, the content of TPicture/TBitmap is automatically released on Assign and this was your answer to zebada. What I meant was that the bitmap you created in UpdateBitmap was never freed. The internal representation is either shared or taken over by the TImage control, but the class as such remains in memory and is allocated again on each UpdateBitmap call.

Ciao, Mike
0
 
interCommented:
Sorry if I a make myself wrong. I am just doing brain storming. You are right, we loose the instance data.
regards, igor
0
 
zebadaAuthor Commented:
Thanks for the discussion, very interesting. (by the way I set 200 points because the question is important to me and I don't like writing/using code or features that I don't FULLY understand).
But I'm still not 100% certain whether or not I need to explicitly execute a mybmp.Free statement.

if I did this:
  bmp = TBitMap.Create;
  Picture.Assign(bmp);
  bmp.Free;
would I not cause problems when the TImage tries to access the (now freed) bitmap instance?

Should bmp be a global variable? (uggh!)

Im just not sure what FImage.Release does. Does it actually free the TBitmap instance that I allocated with my bmp := TBitmap.Create statement?

Sorry for being long winded. You guys help me a lot and I appreciate it :)
0
 
interCommented:
In delphi graphics, there is an image memory manager which allocates data and reference count on it. So when we assign bitmap to picture, they share the same data but the reference count is 2. when you free the bitmap, the image manager DOES NOT dispose the image data beacuse its reference count is dropped to 1 (bmp.free) not 0. so you should free the bitmap and enjoy....
0
 
interCommented:
Actually not an image manager but an a base class calle TSharedImage from which TBitmapImage, TMetafileiamge, ticonimage are derived. So when you assign a bitmap to another, the Referencecount of the TBItmapImage is incremented. WHen a bitmap is destroyed,  reference count is decremented. when reference count is 0 bitmapimage frees itself. By this way unless you modify the one of the bitmaps, the bitmap image is not coppied.
regards, igor
0
 
zebadaAuthor Commented:
Thanks a lot,

Igor answer for the points.


0
All Courses

From novice to tech pro — start learning today.