3

I'm sure this has been asked before, but I couldn't seem to find it. I use the code below to display an Image from a MS Access database. However, I would like know how to do the following:

-Is it possible to take the procedure below and 'call' it in another form?

Scenario: Three Forms. Three Tables, One Database. I access the tables via a TADOTable component and TADOConnection.

Each form has a button (btnShowImage), to show the picture from the datbase. In order for it to currently work, I need to add the function to the form and then in the the btnShowImage.OnClick, I add the procedure as seen below. This happens on all three forms. My question is: Is there anyway to make it more efficient. Since it seems a little tedious adding this code to all three forms, if it basically does the same (bear in mind, that in the procedure, the table name is different on all three forms). Is there a simpler way of doing this (displaying the image), without having to use all this code on each form?

Thanks for any help!

CODE:

...uses
    JPEG, ADODB, DB

function JpegStartsInBlob(PicField: TBlobField): integer;
var
  bS: TADOBlobStream;
  buffer: Word;
  hx: string;
begin
  Result := -1;
  bS := TADOBlobStream.Create(PicField, bmRead);
  try
    while (Result = -1) and (bS.Position + 1 < bS.Size) do begin
      bS.ReadBuffer(buffer, 1);
      hx := IntToHex(buffer, 2);
      if hx = 'FF' then begin
        bS.ReadBuffer(buffer, 1);
        hx := IntToHex(buffer, 2);
        if hx = 'D8' then
          Result := bS.Position - 2
        else if hx = 'FF' then
          bS.Position := bS.Position - 1;
      end;
    end;
  finally
    bS.Free
  end;
end;

procedure Tfrm3.btnShowImageClick(Sender: TObject);
var
  bS: TADOBlobStream;
  Pic: TJPEGImage;
begin
  bS := TADOBlobStream.Create(table1.FieldByName('Photo')
    as TBlobField, bmRead);
  bS.Seek(JpegStartsInBlob(table1.FieldByName('Photo') as TBlobField),
    soFromBeginning);
  Pic := TJPEGImage.Create;
  Pic.LoadFromStream(bS);
  frmOne.Image1.Picture.Graphic := Pic;
  Pic.Free;
  bS.Free;
end;

Code was found on: http://delphi.about.com/od/database/l/aa030601d.htm

Jerry Dodge
  • 26,858
  • 31
  • 155
  • 327
coder123
  • 67
  • 4
  • 10
  • Create new unit and put your procedure there. Then use it in all forms... – Adam Jul 19 '12 at 21:21
  • My thoughts also, but how would I change the table name on each of them? – coder123 Jul 19 '12 at 21:23
  • 1
    Or put it in a [TDataModule](http://www.delphipages.com/forum/showthread.php?t=208044) together with the database connection. – LU RD Jul 19 '12 at 21:23

1 Answers1

5

What I would do if I had code that had to be called from a button on 3 different forms, which was almost the same everywhere except for a few specific differences from the context of each individual form, is take the code, put it in a unit, and turn the differences into parameters. For example:

procedure LoadJPEGImage(field: TBlobField; image: TImage);
var
  bS : TADOBlobStream;
  Pic : TJPEGImage;
begin
  bS := TADOBlobStream.Create(field, bmRead);   
  Pic := TJPEGImage.Create;
  try
    bS.Seek(JpegStartsInBlob(field), soFromBeginning);
    Pic.LoadFromStream(bS);
    image.Picture.Graphic := Pic;
  finally
    Pic.Free;
    bS.Free;
  end;
end;

Now the code doesn't care about the form or any of its details; it just needs a TBlobField to read from and a TImage to draw the picture to, and you can use it on as many forms as you want.

Mason Wheeler
  • 82,511
  • 50
  • 270
  • 477
  • Thats superb, can't believe I didn't think of it. Thanks Mason! – coder123 Jul 19 '12 at 21:35
  • 1
    @Coder123: It's not always obvious. But when you start to look for opportunities to refactor like that, you start to see more patterns where the technique can be useful. :) – Mason Wheeler Jul 19 '12 at 21:38
  • Quick question, how would I get the procedure to initialize on another form, if I declare the form? – coder123 Jul 19 '12 at 21:38
  • @Coder123: What do you mean, initialize on another form? – Mason Wheeler Jul 19 '12 at 21:39
  • Assuming I assigned the field and image parameters its values, how do start/create/begin the procedure? – coder123 Jul 19 '12 at 21:46
  • taking http://pastebin.ca/2172739 u call the procedure like // TSomeForm.OnSomeButtonClick(...); begin ExtractJped(SomeTableOnThisForm.FieldByName(...), SomeImageOnForm.Grahpic)); ned; // like that - what u took in original code was turned into vaiables. That means you should supply those values as variables into procedure. When you call some procedure, IntToHex(i,2) - you pass it two values. For this procudure u would pass the TField and TGraphic objects – Arioch 'The Jul 19 '12 at 21:53
  • Nevermind, my own fault. Got it working. Thanks Mason and Arioch! – coder123 Jul 19 '12 at 22:22
  • Why does it say "Undeclared Identifier: 'TImage'"? Am I missing a declaration or maybe a uses clause somewhere? – coder123 Jul 19 '12 at 22:33
  • @Coder123: Yes, that means you're missing the `uses` for the unit that contains TImage. Try hovering the mouse cursor over the TImage declaration in your form, it should give you the unit that way. Or CTRL-click it. – Mason Wheeler Jul 19 '12 at 22:41
  • Thanks, but I still get it. Not sure why. I have my code on form4 and the image component with the display image button on form3. Both units are linked via uses under implementation on each form. { procedure LoadJPEGImage(field: TBlobField; image: TImage);} The code stops there, at TImage and subsequently at image.Picture.Graphic := Pic. – coder123 Jul 19 '12 at 23:10
  • @coder123: Looks like TImage is declared in the `ExtCtrls` unit. So you need to make sure that you have `ExtCtrls` in the uses clause for the unit you extracted this routine into. – Mason Wheeler Jul 19 '12 at 23:21