1

I'm very new to delphi, doing a project for my A level. When I run my code the images just don't show, I've looked everywhere and my teacher can't help me. Can anyone tell me what I'm missing?

    const
       Animal : array[0..6] of string =                    ('Bears','Dogs','Cats','Chickens','Horses','Cows','Monkeys');
    ImagePaths : array [0..6] of string
      = ('img0.JPG', 'img1.JPG', 'img2.JPG', 'img3.JPG', 'img4.JPG', 'img5.JPG',
        'img6.JPG');

  var i:integer;
  Images : array [0..11] of TImage;

procedure LoadImages;
  var
  k,l:integer;
  begin
  Randomize;
  k:=Random(11);
  for l:= 0 to k do
  begin
    Images[l] := TImage.Create(nil);
    Images[l].Picture.LoadFromFile(ImagePaths[i])
  end

end;

procedure TForm4.FormCreate(Sender: TObject);
begin
randomize;
i:=random(6);
QuestionLbl.Caption:=Format('How many %s are there?',[Animal[i]]);
LoadImages;
end;

The idea is that a random number of images of the same randomly selected animal is displayed for a child to then count and input, if that helps. Much appreciate any help.

edit.

as this is only a prototype I have copied it all to a new application and this is all the code I didn't include:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics,     Controls, Forms,
  Dialogs, StdCtrls,jpeg, ExtCtrls;

type
  TForm1 = class(TForm)
    QuestionLbl: TLabel;
    procedure FormCreate(Sender: TObject);
      private
    { Private declarations }
  public
    { Public declarations }
  end;

The same error is occurring and I'm afraid I'm too ignorant to follow what I'm sure were very clear instructions.

4 Answers4

4

What appears to be missing is that you need to tell the image which control is its parent so that it can appear on screen. Do that like this:

Images[l].Parent := TheForm;

Obviously your form variable will have a different name, but I'm sure you know what it's called.

When you do this you will find that they all end up on top of each other. Assign to the Top and Left properties to position then. Finally you will likely want to set the Height and Width properties of the images to match the dimensions of the images, Images[l].Picture.Height and Images[l].Picture.Width.


I can't imagine why your code produces an access violation but it's presumably unrelated to the question you asked. The following code proves that what I say above is correct:

procedure TMyForm.FormCreate(Sender: TObject);
var
  Image: TImage;
begin
  Image := TImage.Create(Self);
  Image.Parent := Self;
  Image.Picture.LoadFromFile('C:\desktop\image.jpg');
  Image.Top := 0;
  Image.Left := 0;
  Image.Height := Image.Picture.Height;
  Image.Width := Image.Picture.Width;
end;

Without your full code I cannot debug your AV.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
1

TImage component must to be painted on the screen, for do so make a 1pixel panel as the parent to load the graphics. like in a loading screen so the images can be used as default TImage procedures.

Nickname
  • 11
  • 2
1

Why you just don't put your TImages on the form, and just LoadFromFile the ones you want to show ? Appear to me that would be easier.

But: what you trying to accomplish? From the code, I can imagine you were trying to show a number of images to people count them and answer the question...

So, if you add (and position) the 11 empty(no image) TImages in the form, you can do:

// Any trouble in copying your FormCreate header, David? ;-)
procedure TMyForm.FormCreate(Sender: TObject);
begin
  Images[0] := Image_N1; // First TImage
  Images[1] := Image_N2;
  Images[2] := Image_N3;
  // Do that until the 12 slots are filled
  // As a exercise for Danny Robinson( the OP ), you can do that in a for..do using 
  // the Form.Components array property to automate it instead of 
  // doing one-at-a-line
end;

procedure ClearImages;
var I: Integer;
begin
  for I = Low(Images) to High(Images) do
  begin
    Images.Picture.Graphic := Nil;
  end;
end;



procedure LoadImages;
var
  k,l:integer;
begin
  ClearImages;
  Randomize;
  k:=Random(11);
  for l:= 0 to k do
  begin
    Images[l].Picture.LoadFromFile(ImagePaths[i])
  end;

end;

If you still need to create the TImages on the fly, just create the 12 TImages once on FormCreate (as in David's answer) and keep calling the LoadImages.

EDIT:

Some ideas, since you are learning.
Creating visual controls on-the-fly is a very boring(in my opinion, of course) task that involves:

  • Creating the object, obviously
  • Assigning it to a parent control (forms doesn't need this pass)
  • Sizing it accordingly to your visual planning
  • Positioning it in the place of the parent control you want it to be
  • Set it's anchors, for it to reposition and/or resize when the parent control is resized (if needed)
  • Only after all this, make it do what you want it to do (in this case, showing images).

Almost all those steps David Heffernan's answer show the code for it. But, unless you really need a dynamic layout, doing all those on design-time is more practical ;-)

Community
  • 1
  • 1
Fabricio Araujo
  • 3,810
  • 3
  • 28
  • 43
  • your absolutely right, that's how I had originally planned to code it, but tried what i've posted for testing. Someone saved and logged me of when I went to lunch at school. Thank you, I'll give this a try. – Danny Robinson Oct 02 '11 at 11:14
  • I was somehow under the illusion that having array[0..11] of TImage automatically put all TImage on the form into the array. Hopefully I can find someone else to blame. I don't have access to my computer at the moment but I imagine this should work. Thank you all very much for your help. – Danny Robinson Oct 02 '11 at 11:31
1

You need to set the Parent property of each TImage in order to see them onscreen. You can't use the global Form pointer variable, though, because it has not been assigned yet when the OnCreate event is triggered. So pass in the form's Self pointer as a parameter of LoadImages() instead.

You have another bug - you declared a 12-element TImage array but declared a 7-element String array for the image paths. The way you are using Random(), if it generates a value above 6, you will go out of bounds of the String array.

Try this instead:

const
  ...
  ImagePaths : array [0..6] of string = ('img0.JPG', 'img1.JPG', 'img2.JPG', 'img3.JPG', 'img4.JPG', 'img5.JPG', 'img6.JPG');

var
  i: integer;
  Images : array [0..6] of TImage;

procedure LoadImages(AParent: TWinControl);
var
  i, k: integer;
begin
  Randomize;
  k := Random(7);
  for i := 0 to k do
  begin
    Images[i] := TImage.Create(nil);
    Images[I].Parent := AParent;
    // set other properties, like Left/Top...
    Images[l].Picture.LoadFromFile(ImagePaths[i]);
  end;
end;

procedure TForm4.FormCreate(Sender: TObject);
begin
  ...
  LoadImages(Self);
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • +1. It would be a better answer if you changed `k := Random(7)` to `k := Random(High(Images) + 1)`, though. Unnecessary hardcoded limits, especially in posts to newcomers, are just nasty; they set a bad example. :) – Ken White Oct 01 '11 at 00:55
  • I think the form variable typically is assigned very early if Application.CreateForm is called. It is assigned after the call to NewInstance and before constructor is called if memory serves. – David Heffernan Oct 01 '11 at 12:35