TAZI
asked on
Loading Images at Runtime
Hi,
I would like to load images into my program but this should happen only at runtime. The reason being, I am loading a logo for different companies for eg) If I am working on a CompanyA's data, then a logo for (CompanyA) should be visible in the right hand corner or it I am working with COmpanyB's data then a logo for (CompanyB) must appear in place of the logo of CompanyA. The image loading must be dynamic as new clients are loaded into the system all the time. I have thought of loading the images from disk but this slows down the speed of the system as I have to use load from file all the time, I don't mind using load from file on start up (OnFormCreate). Is there a way to load images into an imagelist at runtime then I can load the images into the imagelist at runtime and then change the logo as the client changes.
Thanks for your help in advance
Regards
TAZI
I would like to load images into my program but this should happen only at runtime. The reason being, I am loading a logo for different companies for eg) If I am working on a CompanyA's data, then a logo for (CompanyA) should be visible in the right hand corner or it I am working with COmpanyB's data then a logo for (CompanyB) must appear in place of the logo of CompanyA. The image loading must be dynamic as new clients are loaded into the system all the time. I have thought of loading the images from disk but this slows down the speed of the system as I have to use load from file all the time, I don't mind using load from file on start up (OnFormCreate). Is there a way to load images into an imagelist at runtime then I can load the images into the imagelist at runtime and then change the logo as the client changes.
Thanks for your help in advance
Regards
TAZI
ASKER
Hi Mike ...
I don't want to load images into the resource file of the executable because then I have to continually recompile my program if a new client is added.
If I store images on the disk and I use LoadFromFile each time .. it slows down the application.
SO, I think the 3rd option miight be the one. If my images are stored on the local harddrive (c:\images) folder can you show me some code to load these images into a ImageList but this must happen at runtime only.
Regard
TAZI
I don't want to load images into the resource file of the executable because then I have to continually recompile my program if a new client is added.
If I store images on the disk and I use LoadFromFile each time .. it slows down the application.
SO, I think the 3rd option miight be the one. If my images are stored on the local harddrive (c:\images) folder can you show me some code to load these images into a ImageList but this must happen at runtime only.
Regard
TAZI
Hi Tazi,
Image1.Picture.Loadfromfil e('C:\wind ows\Red Blocks.bmp');
Asw
Image1.Picture.Loadfromfil
Asw
ASKER
Hi ..
I mentioned above that I don't want to load directly from the local hard drive with loadfromfile ... it works to slowly over a network. I want to load theses into a string list on startup and then refer to these images from the image list as I make use of the program
I want to load images at startup
Regards
TAZI
I mentioned above that I don't want to load directly from the local hard drive with loadfromfile ... it works to slowly over a network. I want to load theses into a string list on startup and then refer to these images from the image list as I make use of the program
I want to load images at startup
Regards
TAZI
Image1.Picture.LoadFromFil e('file.ex t');
For example, if pictures in folder \splash\ in program install folder:
in OnCreate:
var
SpFile : String;
....
SpFile := ExtractFilePath(Applicatio n.ExeName) ;
If (SpFile[Length(SpFile)]<>' \') And
(SpFile[Length(SpFile)]<>' /') Then
SpFile := SpFile+'\';
// function SelectSplash() return a
// splash file name for current firm ID
SpFile := SpFile+'splash\'+SelectSpl ash;
// Load into SpImage - TImage with splash
SpImage.Picture.LoadFromFi le(SpFile) ;
....
For example, if pictures in folder \splash\ in program install folder:
in OnCreate:
var
SpFile : String;
....
SpFile := ExtractFilePath(Applicatio
If (SpFile[Length(SpFile)]<>'
(SpFile[Length(SpFile)]<>'
SpFile := SpFile+'\';
// function SelectSplash() return a
// splash file name for current firm ID
SpFile := SpFile+'splash\'+SelectSpl
// Load into SpImage - TImage with splash
SpImage.Picture.LoadFromFi
....
ASKER
Hi, lmikle
I donot want to load the image from a file ...... there are multiple images that need to be accessed. Each time I select a client in the combobox, the image changes. I want to access these images from a imagelist or something to that effect.
Regards
TAZI
I donot want to load the image from a file ...... there are multiple images that need to be accessed. Each time I select a client in the combobox, the image changes. I want to access these images from a imagelist or something to that effect.
Regards
TAZI
For loading Images into TImageList;
1st set a Width and Height properties if TImageList to max Width and Height of your images (it's in disign time recomended).
In loop:
2nd load a image into Bitmap (LoadFromFile)
3rd insert this bitmap into TImageList:
ImageList1.Add(Bitmap,nil) ;
1st set a Width and Height properties if TImageList to max Width and Height of your images (it's in disign time recomended).
In loop:
2nd load a image into Bitmap (LoadFromFile)
3rd insert this bitmap into TImageList:
ImageList1.Add(Bitmap,nil)
ASKER
Hi, lmikle
I am having a problem with step 2 ..
Loading from local c drive into imagelist
give me some code please
Regards
TAZI
I am having a problem with step 2 ..
Loading from local c drive into imagelist
give me some code please
Regards
TAZI
Oh, quite hectical conversation here :-) TAZI please use the FileLoad command I gave you already. Please all your images you want to have into one bitmap (each close to another, into one line) and use the resulting bitmap as parameter for FileLoad. I think you should set the size of the image list just before the call to FileLoad then it will automatically split the images and you can access them separately.
Ciao, Mike
Ciao, Mike
ASKER
Hi Mike
I may come across as an idiot, but I am totally lost here.
I have 3 BMP's name
ImageNo1.bmp ImageNo2.bmp and ImageNo3.bmp they all reside in
the (c:\images) folder. I want to load all 3 images into the imagelist on click of a button.
I used
TCustomImageList.FileLoad( 'c:\Images \ImageNo1. bmp');
and I get the ffg error
Incompatible type TResType and String
Sorry ... but I am totally lost here
HELP
Regards
TAZI
I may come across as an idiot, but I am totally lost here.
I have 3 BMP's name
ImageNo1.bmp ImageNo2.bmp and ImageNo3.bmp they all reside in
the (c:\images) folder. I want to load all 3 images into the imagelist on click of a button.
I used
TCustomImageList.FileLoad(
and I get the ffg error
Incompatible type TResType and String
Sorry ... but I am totally lost here
HELP
Regards
TAZI
No problem TAZI, we all have our dark days :-) Actually, the call should be:
FileLoad(rtBitmap, 'c:\Images\ImageNo1.bmp', clFuchsia);
where clFuchsia is a color which you should use in your bitmap for transparent parts (if you need this color for the image then use another one).
Ciao, Mike
FileLoad(rtBitmap, 'c:\Images\ImageNo1.bmp', clFuchsia);
where clFuchsia is a color which you should use in your bitmap for transparent parts (if you need this color for the image then use another one).
Ciao, Mike
ASKER
Hi Mike
I USED the statement as ffg
TCustomImageList.FileLoad( rtBitmap, 'c:\Images\ImageNo1.bmp', clFuchsia);
and I get the ffg error
This form of method call only allowed for class methods.
More Help Please
Regards
TAZI
I USED the statement as ffg
TCustomImageList.FileLoad(
and I get the ffg error
This form of method call only allowed for class methods.
More Help Please
Regards
TAZI
TAZI, I assumed you are aware of the fact that you cannot call it directly this way. Replace TCustomImageList in the above example with your actual image list instance:
var
IL: TImageList;
begin
IL := TImageList.Create;
IL.Width := 32;
IL.Height := 32;
IL.FileLoad(rtBitmap, 'c:\Images\ImageNo1.bmp', clFuchsia);
........
end;
Ciao, Mike
var
IL: TImageList;
begin
IL := TImageList.Create;
IL.Width := 32;
IL.Height := 32;
IL.FileLoad(rtBitmap, 'c:\Images\ImageNo1.bmp', clFuchsia);
........
end;
Ciao, Mike
ASKER
Hi, Mike
Thanks ... I got that part working
Now, what about loading there 3 images into a TIMAGE component
Regards
TAZI
Thanks ... I got that part working
Now, what about loading there 3 images into a TIMAGE component
Regards
TAZI
Don't use a TImage component for this special case. If I understand you correctly then you just want to display a logo out of serveral stored in the image list, right? So instead place a TPaintBox onto the place where the image should appear and in its OnPaint handler you just do an IL.Draw(Canvas, X, Y, Index, True); where Canvas is the canvas of the parent (usually the form or if you have placed the paint box onto a panel this panel's canvas), X and Y the position where to draw (if the paint box is already correctly located and sized then use 0, 0 there) and finally the index of the image you want to draw.
Ciao, Mike
Ciao, Mike
ASKER
Hi Mike
You're correct I only want to display the company logo which is stored in the Image List. So by placing a Tpaintbox component ... how do I load the image
what statement to use
Regards
TAZI
You're correct I only want to display the company logo which is stored in the Image List. So by placing a Tpaintbox component ... how do I load the image
what statement to use
Regards
TAZI
TAZI, you already have loaded the images into the image list. Now you want to display it. Since you have the image in the image list you just have to draw it (without loading it into another container like TImage). So place a TPaintBox component on the place where the logo should appear and make it the correct size. Assign an OnPaint handler and write:
procedure TForm1.PaintBox1Paint(Send er: TObject);
begin
IL.Draw(Canvas, 0, 0, 0, True);
end;
where IL is the image list into which you have loaded the company logos.
Ciao, Mike
procedure TForm1.PaintBox1Paint(Send
begin
IL.Draw(Canvas, 0, 0, 0, True);
end;
where IL is the image list into which you have loaded the company logos.
Ciao, Mike
ASKER
Hi Mike
I have done as you say but no logos seem to appear
Regards
TAZI
I have done as you say but no logos seem to appear
Regards
TAZI
Tazi,
When using TImageList
1.) The bitmaps must all be the same size,
for example: if you have 3 bitmaps, they all must be same size.
example: 25 X 25
Then they must be combined to form a single bitmap. example: 75 X 25
The TImageList will break them apart by using its Height & Width properties
In this example you would set your height & width to 25 & 25 respectively
To load the image you would call
the
TimageList's FileLoad method
Example:ImageList1.FileLoa d(rtBitmap , 'C:\Text.bmp',clBlack);
The image list is capable of holding a large number of same sized images and retrieving them via their index within the range 0 to n - 1. The image list also has methods to facilitate storing, retrieving, and drawing of the stored images.
Hope this helps!
Shane
When using TImageList
1.) The bitmaps must all be the same size,
for example: if you have 3 bitmaps, they all must be same size.
example: 25 X 25
Then they must be combined to form a single bitmap. example: 75 X 25
The TImageList will break them apart by using its Height & Width properties
In this example you would set your height & width to 25 & 25 respectively
To load the image you would call
the
TimageList's FileLoad method
Example:ImageList1.FileLoa
The image list is capable of holding a large number of same sized images and retrieving them via their index within the range 0 to n - 1. The image list also has methods to facilitate storing, retrieving, and drawing of the stored images.
Hope this helps!
Shane
TAZI, send me your sample project (public@lischke-online.de) and I will have a look at it.
Ciao, Mike
Ciao, Mike
just read all this thread,
nice work,
nice end ;-)
Igor
nice work,
nice end ;-)
Igor
Why use an ImageList? Why not use a stringlist and add objects to the string? Here, an example:
Create a new application with one form. Add a TListBox and a TImage to it. Then use the following code:
<code>
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls;
type
TForm1 = class(TForm)
ListBox1: TListBox;
Image1: TImage;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
private
List: TStringList;
public
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
const
Path = 'C:\WinNT\';
var
Search: TSearchRec;
Error: Integer;
Bmp: TBitmap;
begin
List := TStringList.Create;
Error := FindFirst(Path + '*.bmp', faAnyFile - faDirectory, Search);
if (Error = 0) then begin
while (Error = 0) do begin
Bmp := TBitmap.Create;
Bmp.LoadFromFile(Path + Search.Name);
List.AddObject(Search.Name , Bmp);
Error := FindNext(Search);
end;
FindClose(Search);
end;
ListBox1.Items.AddStrings( List);
end;
procedure TForm1.FormDestroy(Sender: TObject);
var
I: Integer;
begin
for I := 0 to List.Count - 1 do begin
if assigned(List.Objects[I]) and (List.Objects[I] is TBitmap) then begin
(List.Objects[I] as TBitmap).Free;
end;
end;
end;
procedure TForm1.ListBox1Click(Sende r: TObject);
var
I: Integer;
begin
I := List.IndexOf(ListBox1.Item s[ListBox1 .ItemIndex ]);
if (I >= 0) then begin
if assigned(List.Objects[I]) and (List.Objects[I] is TBitmap) then begin
Image1.Picture.Bitmap.Assi gn(List.Ob jects[I] as TBitmap);
end;
end;
end;
end.
</code>
Okay, on the OnCreate, a list of all bitmaps in my WinNT folder is created and all images are read into this list. A copy of these names are stored in th TListBox.
On the OnDestroy I delete all images again.
Finally, in the OnClick event of the listbox, the right bitmap is shown in the TImage.
It doesn't matter which method you use to fill the list. But just by using the Objects property of a stringlist you can store your logo's at the start of the application and you won't have to reload them afterwards.
And even better: the logo's can differ in size.
And to create the list, you can use above method and search for the files, or store the filenames in an INI file and let the application read these names. Or whatever method you prefer.
Keep It Simple, S.....!
Create a new application with one form. Add a TListBox and a TImage to it. Then use the following code:
<code>
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls;
type
TForm1 = class(TForm)
ListBox1: TListBox;
Image1: TImage;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
private
List: TStringList;
public
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
const
Path = 'C:\WinNT\';
var
Search: TSearchRec;
Error: Integer;
Bmp: TBitmap;
begin
List := TStringList.Create;
Error := FindFirst(Path + '*.bmp', faAnyFile - faDirectory, Search);
if (Error = 0) then begin
while (Error = 0) do begin
Bmp := TBitmap.Create;
Bmp.LoadFromFile(Path + Search.Name);
List.AddObject(Search.Name
Error := FindNext(Search);
end;
FindClose(Search);
end;
ListBox1.Items.AddStrings(
end;
procedure TForm1.FormDestroy(Sender:
var
I: Integer;
begin
for I := 0 to List.Count - 1 do begin
if assigned(List.Objects[I]) and (List.Objects[I] is TBitmap) then begin
(List.Objects[I] as TBitmap).Free;
end;
end;
end;
procedure TForm1.ListBox1Click(Sende
var
I: Integer;
begin
I := List.IndexOf(ListBox1.Item
if (I >= 0) then begin
if assigned(List.Objects[I]) and (List.Objects[I] is TBitmap) then begin
Image1.Picture.Bitmap.Assi
end;
end;
end;
end.
</code>
Okay, on the OnCreate, a list of all bitmaps in my WinNT folder is created and all images are read into this list. A copy of these names are stored in th TListBox.
On the OnDestroy I delete all images again.
Finally, in the OnClick event of the listbox, the right bitmap is shown in the TImage.
It doesn't matter which method you use to fill the list. But just by using the Objects property of a stringlist you can store your logo's at the start of the application and you won't have to reload them afterwards.
And even better: the logo's can differ in size.
And to create the list, you can use above method and search for the files, or store the filenames in an INI file and let the application read these names. Or whatever method you prefer.
Keep It Simple, S.....!
ASKER
Hi All,
I make use of the ffg Code to Insert images into the ImageList
ImageList1.Width := 165;
ImageList1.Height := 118;
ImageList1.FileLoad(rtBitm ap, 'c:\ImageLists\Logo1.bmp', clFuchsia);
I don't think the image is loading into the Image List and thus it cannot be displayed with the following code.
ImageList1.Draw(Canvas, 0, 0, 0, True);
I tested it by physically adding an image to the imagelist at design time and then I execute
ImageList1.Draw(Canvas, 0, 0, 0, True);
and the image loads at the top left corner of the form.
I also would appreciate it if anyone can assist me in loading this image into a TIMAGE Component.
Thanks in advance for your help, it is greatly appreciated
Regards
TAZI
I make use of the ffg Code to Insert images into the ImageList
ImageList1.Width := 165;
ImageList1.Height := 118;
ImageList1.FileLoad(rtBitm
I don't think the image is loading into the Image List and thus it cannot be displayed with the following code.
ImageList1.Draw(Canvas, 0, 0, 0, True);
I tested it by physically adding an image to the imagelist at design time and then I execute
ImageList1.Draw(Canvas, 0, 0, 0, True);
and the image loads at the top left corner of the form.
I also would appreciate it if anyone can assist me in loading this image into a TIMAGE Component.
Thanks in advance for your help, it is greatly appreciated
Regards
TAZI
TAZI,
I got your eMails regarding this problem here, but I must say you are yourself not quite clear what you really want, do you? Or is it that you have difficulties to describe the problem?
Let me try to pool what we have so far:
1) You have logo files. One separate file for each company.
2) You want to display the logo whenever the client works with data of a certain company.
3) You don't want to make the output to complicated.
4) Switching the company in the program will not happen very often.
So my advice is just to load the image from disk when ever it is needed. Btw. you should use the same name for the disk file and the parameter to load the image. I modified your code to:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ImgList, jpeg, ExtCtrls, Buttons;
type
TForm1 = class(TForm)
Button1: TButton;
Image1: TImage;
BitBtn1: TBitBtn;
Panel1: TPanel;
procedure Button1Click(Sender: TObject);
private
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender : TObject);
begin
Image1.Picture.LoadFromFil e(ExtractF ilePath(Ap plication. ExeName) + 'NPC.bmp');
end;
end.
object Form1: TForm1
Left = 423
Top = 390
Width = 696
Height = 480
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Image1: TImage
Left = 176
Top = 176
Width = 176
Height = 120
AutoSize = True
end
object Button1: TButton
Left = 152
Top = 96
Width = 225
Height = 25
Caption = 'LOAD INTO IMAGE LIST'
TabOrder = 0
OnClick = Button1Click
end
object BitBtn1: TBitBtn
Left = 152
Top = 128
Width = 225
Height = 25
Caption = 'LOAD INTO IMAGE'
TabOrder = 1
end
object Panel1: TPanel
Left = 424
Top = 40
Width = 225
Height = 185
Caption = 'Panel1'
TabOrder = 2
end
end
Ciao, Mike
I got your eMails regarding this problem here, but I must say you are yourself not quite clear what you really want, do you? Or is it that you have difficulties to describe the problem?
Let me try to pool what we have so far:
1) You have logo files. One separate file for each company.
2) You want to display the logo whenever the client works with data of a certain company.
3) You don't want to make the output to complicated.
4) Switching the company in the program will not happen very often.
So my advice is just to load the image from disk when ever it is needed. Btw. you should use the same name for the disk file and the parameter to load the image. I modified your code to:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ImgList, jpeg, ExtCtrls, Buttons;
type
TForm1 = class(TForm)
Button1: TButton;
Image1: TImage;
BitBtn1: TBitBtn;
Panel1: TPanel;
procedure Button1Click(Sender: TObject);
private
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender
begin
Image1.Picture.LoadFromFil
end;
end.
object Form1: TForm1
Left = 423
Top = 390
Width = 696
Height = 480
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Image1: TImage
Left = 176
Top = 176
Width = 176
Height = 120
AutoSize = True
end
object Button1: TButton
Left = 152
Top = 96
Width = 225
Height = 25
Caption = 'LOAD INTO IMAGE LIST'
TabOrder = 0
OnClick = Button1Click
end
object BitBtn1: TBitBtn
Left = 152
Top = 128
Width = 225
Height = 25
Caption = 'LOAD INTO IMAGE'
TabOrder = 1
end
object Panel1: TPanel
Left = 424
Top = 40
Width = 225
Height = 185
Caption = 'Panel1'
TabOrder = 2
end
end
Ciao, Mike
ASKER
Hi Mike
I may be confusing you and at the same time driving you crazy. Sorry about that.
OKAY ... LET ME TRY AND BE MORE PRECISE.
I have large volumes of data. Certain people belonging to certian clients. Eg).
200 people for "CLIENTA", 300 people for "CLIENT B", 500 people for "CLIENT C" and so on. There are approximately 30 Clients and it may increase at a later stage. so in actual fact there are some 30 logo's that I am working with.
1) You have logo files. One separate file for each company. - THIS IS CORRECT -
2) You want to display the logo whenever the client works with data of a certain company. - THIS IS CORRECT -
The user can search through the search engine for all surnames - "MAHOMED" This will bring back data for all Clients in alphabetical order .. Surname and Initial and Account Number.
So I may find 2 Client A's, then 4 Client B's than 1 Client C and so on with the Surname Mahomed AND Initial A.
Now, as I browze through this list the logo must change depending on which Client I am working with.
The system is going to function on a network. The exe is placed on the server and there are shortcuts to some 60 machines all sharing the application.
I do not want to make use of a LoadFromFile. I want to use the Image List. I want to load these logo's on Startup of the program into the ImageList and then access them from the ImageList as the client changes when I select the next record from the combobox.
The Client can change often so loading from disk is not a good idea.
Hope I have made myself clear.
SORRY FOR THE INCONVENIENCE AND I APPRECIATE ALL YOUR TIME AND EFFORT
Regards
TAZI
I may be confusing you and at the same time driving you crazy. Sorry about that.
OKAY ... LET ME TRY AND BE MORE PRECISE.
I have large volumes of data. Certain people belonging to certian clients. Eg).
200 people for "CLIENTA", 300 people for "CLIENT B", 500 people for "CLIENT C" and so on. There are approximately 30 Clients and it may increase at a later stage. so in actual fact there are some 30 logo's that I am working with.
1) You have logo files. One separate file for each company. - THIS IS CORRECT -
2) You want to display the logo whenever the client works with data of a certain company. - THIS IS CORRECT -
The user can search through the search engine for all surnames - "MAHOMED" This will bring back data for all Clients in alphabetical order .. Surname and Initial and Account Number.
So I may find 2 Client A's, then 4 Client B's than 1 Client C and so on with the Surname Mahomed AND Initial A.
Now, as I browze through this list the logo must change depending on which Client I am working with.
The system is going to function on a network. The exe is placed on the server and there are shortcuts to some 60 machines all sharing the application.
I do not want to make use of a LoadFromFile. I want to use the Image List. I want to load these logo's on Startup of the program into the ImageList and then access them from the ImageList as the client changes when I select the next record from the combobox.
The Client can change often so loading from disk is not a good idea.
Hope I have made myself clear.
SORRY FOR THE INCONVENIENCE AND I APPRECIATE ALL YOUR TIME AND EFFORT
Regards
TAZI
Well, this makes it a lot clearer to me :-) Since I saw of what size the logos are I still recommend using TImage instead of TImageList. If I were you I would create an array of TImage (TBitmap would be enough too) and load the images either from a network drive, a database or the application's resouce.
This would then be quite similar to what Workshop_alex wrote. Selecting the appropriate image is then simply indexing into the list. Use TImage.Picture.Graphic := TBitmap(FList.Objects[Inde x]); to actually show the image.
Ciao, Mike
This would then be quite similar to what Workshop_alex wrote. Selecting the appropriate image is then simply indexing into the list. Use TImage.Picture.Graphic := TBitmap(FList.Objects[Inde
Ciao, Mike
ASKER
Hi Workshop_Alex,
Just wanted to ask you if the same code can be used for JPEG images and not Bitmaps.
Regards
TAZI
Just wanted to ask you if the same code can be used for JPEG images and not Bitmaps.
Regards
TAZI
No, the code does not work for jpeg. I only works for bmps. Some extra steps are needed to load images which are not bmps. You can download my GraphicEx library from www.lischke-online.de/Graphics.html which contains a sample to load various image formats (gif, rle, dib, psp, psd, tif, jpeg, tga....).
Ciao, Mike
Ciao, Mike
My version could be used for all kinds of objects. Bitmaps, JPeG's, GIF's, sounds, buttons, whatever you want. That's just the strength behind the TStrings Object property. You can add objects to a stringlist. Use the list as an index for the Objects in the list.
One drawback: you must create and free the objects yourself. In my code-sample I've added TBitmap objects. With Delphi 4 and 5 you can also find a unit called JPEG.pas. (and actually a complete JPEG package.) You could use this unit and create TJPEGImage objects in stead of TBitmap objects.
You could even mix TBitmaps and TJPEGImage. Since all you need to do to free an object is calling the Free method, freeing the objects in the list is done like this:
<code>
procedure TForm1.FormDestroy(Sender: TObject);
var
I: Integer;
begin
for I := 0 to List.Count - 1 do begin
if assigned(List.Objects[I]) and (List.Objects[I] is TObject) then begin
(List.Objects[I] as TObject).Free;
end;
end;
end;
</code>
I've only used TBitmap before in this code-part to keep the code more clear... But replace every TBitmap by TJPEGImage and you're creating a list of JPeG files. And assigning them to the TImage can be done with the same method as the TBitmap.
One drawback: you must create and free the objects yourself. In my code-sample I've added TBitmap objects. With Delphi 4 and 5 you can also find a unit called JPEG.pas. (and actually a complete JPEG package.) You could use this unit and create TJPEGImage objects in stead of TBitmap objects.
You could even mix TBitmaps and TJPEGImage. Since all you need to do to free an object is calling the Free method, freeing the objects in the list is done like this:
<code>
procedure TForm1.FormDestroy(Sender:
var
I: Integer;
begin
for I := 0 to List.Count - 1 do begin
if assigned(List.Objects[I]) and (List.Objects[I] is TObject) then begin
(List.Objects[I] as TObject).Free;
end;
end;
end;
</code>
I've only used TBitmap before in this code-part to keep the code more clear... But replace every TBitmap by TJPEGImage and you're creating a list of JPeG files. And assigning them to the TImage can be done with the same method as the TBitmap.
Better is to use TPicture then you don't need to care about TBitmap, TJPEGImage, TIcon, whatever.
Ciao, Mike
Ciao, Mike
<code>
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, JPeG;
type
TForm1 = class(TForm)
ListBox1: TListBox;
Image1: TImage;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
private
List: TStringList;
public
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
const
Path = 'C:\Documents and Settings\Administrator.WIM \Mijn documenten\Mijn afbeeldingen\';
var
Search: TSearchRec;
Error: Integer;
Bmp: TJPEGImage;
begin
List := TStringList.Create;
Error := FindFirst(Path + '*.jpg', faAnyFile - faDirectory, Search);
if (Error = 0) then begin
while (Error = 0) do begin
Bmp := TJPEGImage.Create;
Bmp.LoadFromFile(Path + Search.Name);
List.AddObject(Search.Name , Bmp);
Error := FindNext(Search);
end;
FindClose(Search);
end;
ListBox1.Items.AddStrings( List);
end;
procedure TForm1.FormDestroy(Sender: TObject);
var
I: Integer;
begin
for I := 0 to List.Count - 1 do begin
if assigned(List.Objects[I]) and (List.Objects[I] is TObject) then begin
(List.Objects[I] as TObject).Free;
end;
end;
end;
procedure TForm1.ListBox1Click(Sende r: TObject);
var
I: Integer;
begin
I := List.IndexOf(ListBox1.Item s[ListBox1 .ItemIndex ]);
if (I >= 0) then begin
if assigned(List.Objects[I]) and (List.Objects[I] is TJPEGImage) then begin
Image1.Picture.Bitmap.Assi gn(List.Ob jects[I] as TJPEGImage);
end;
end;
end;
end.
</code>
Above code for D5 proved to me that it also works with JPeG's... But remember: storing large images in memory requires lots of (virtual) memory. And if Virtual memory is used, then it will slow down a bit. But not as slow as loading files from the network...
In this code I've used descendants of TGraphic. This means that icons, bitmaps, metafiles and, if you have the JPEG unit, JPeG files.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, JPeG;
type
TForm1 = class(TForm)
ListBox1: TListBox;
Image1: TImage;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
private
List: TStringList;
public
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
const
Path = 'C:\Documents and Settings\Administrator.WIM
var
Search: TSearchRec;
Error: Integer;
Bmp: TJPEGImage;
begin
List := TStringList.Create;
Error := FindFirst(Path + '*.jpg', faAnyFile - faDirectory, Search);
if (Error = 0) then begin
while (Error = 0) do begin
Bmp := TJPEGImage.Create;
Bmp.LoadFromFile(Path + Search.Name);
List.AddObject(Search.Name
Error := FindNext(Search);
end;
FindClose(Search);
end;
ListBox1.Items.AddStrings(
end;
procedure TForm1.FormDestroy(Sender:
var
I: Integer;
begin
for I := 0 to List.Count - 1 do begin
if assigned(List.Objects[I]) and (List.Objects[I] is TObject) then begin
(List.Objects[I] as TObject).Free;
end;
end;
end;
procedure TForm1.ListBox1Click(Sende
var
I: Integer;
begin
I := List.IndexOf(ListBox1.Item
if (I >= 0) then begin
if assigned(List.Objects[I]) and (List.Objects[I] is TJPEGImage) then begin
Image1.Picture.Bitmap.Assi
end;
end;
end;
end.
</code>
Above code for D5 proved to me that it also works with JPeG's... But remember: storing large images in memory requires lots of (virtual) memory. And if Virtual memory is used, then it will slow down a bit. But not as slow as loading files from the network...
In this code I've used descendants of TGraphic. This means that icons, bitmaps, metafiles and, if you have the JPEG unit, JPeG files.
You have used a descentant of TGraphic, correct, it is TJPEGImage, but this will not allow to load icons, metafiles etc. Again, try TPicture. Btw: you can shorten the lines:
if assigned(List.Objects[I]) and (List.Objects[I] is TJPEGImage) then
Image1.Picture.Bitmap.Assi gn(List.Ob jects[I] as TJPEGImage);
to
if Assigned(List.Objects[I]) then
Image1.Picture.Graphic := TGraphic(List.Objects[I]);
This will free you from checking all the possible image types...
Ciao, Mike
if assigned(List.Objects[I]) and (List.Objects[I] is TJPEGImage) then
Image1.Picture.Bitmap.Assi
to
if Assigned(List.Objects[I]) then
Image1.Picture.Graphic := TGraphic(List.Objects[I]);
This will free you from checking all the possible image types...
Ciao, Mike
Lischke, I prefer the TGraphic as base component. But since I know which type the image is going to be, it's easier to just use TBitmap to TJPEGImage. Especially if you're going to create a list of objects, then you might prefer the ones that take the least size. TPicture has more overhead than just TBitmap or TJPEGImage...
ASKER
Hi Workshop_Alex
I have adjusted and modified your code.
Instead of using a TListbox, I declared an array of type TJPEGImage and I make use of this array to load the appropriate logo.
Is it more Resource intensive, will the program use more memory if I allocate these images to an Array.
You see....Some Clients make use of the same logo so I have to load the appropriate logo as the change is made. On Change of a the Combobox ....
Please advise accordingly
Thanks for your efforts.
Both you and Lischke have provided me with tons of information and I am very greatful.
Regards
TAZI
I have adjusted and modified your code.
Instead of using a TListbox, I declared an array of type TJPEGImage and I make use of this array to load the appropriate logo.
Is it more Resource intensive, will the program use more memory if I allocate these images to an Array.
You see....Some Clients make use of the same logo so I have to load the appropriate logo as the change is made. On Change of a the Combobox ....
Please advise accordingly
Thanks for your efforts.
Both you and Lischke have provided me with tons of information and I am very greatful.
Regards
TAZI
And about using begin-end or not... I prefer to use begin-end to make the code a bit more readable...
I could also have used this:
<code>
if assigned(List.Objects[I]) and (List.Objects[I] is TGraphic) then begin
Image1.Picture.Bitmap.Assi gn(List.Ob jects[I] as TGraphic);
end;
</code>
And I prefer to check the type of the object in the stringlist. This allows me to store more in the list than just graphics...
And using TPicture in stead of TGraphic descendants? It's a matter of taste and preferences. The TGraphic descendants are smaller and slightly faster than TPicture.
If you know that all images will be of one graphic type, then just use the right TGraphic descendant. Else use the TPicture object.
I could also have used this:
<code>
if assigned(List.Objects[I]) and (List.Objects[I] is TGraphic) then begin
Image1.Picture.Bitmap.Assi
end;
</code>
And I prefer to check the type of the object in the stringlist. This allows me to store more in the list than just graphics...
And using TPicture in stead of TGraphic descendants? It's a matter of taste and preferences. The TGraphic descendants are smaller and slightly faster than TPicture.
If you know that all images will be of one graphic type, then just use the right TGraphic descendant. Else use the TPicture object.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
TAZI, using an array takes even less resources but requires you to maintain the length of the array. You might consider using a TList instead.
<code>
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, JPeG, Psock, NMTime;
type
TForm1 = class(TForm)
ListBox1: TListBox;
Image1: TImage;
NMTime1: TNMTime;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
private
//List: TStringList;
List: TList;
public
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
const
Path = 'C:\Documents and Settings\Administrator.WIM \Mijn documenten\Mijn afbeeldingen\';
var
Search: TSearchRec;
Error: Integer;
Bmp: TJPEGImage;
begin
//List := TStringList.Create;
List := TList.Create;
Error := FindFirst(Path + '*.jpg', faAnyFile - faDirectory, Search);
if (Error = 0) then begin
while (Error = 0) do begin
Bmp := TJPEGImage.Create;
Bmp.LoadFromFile(Path + Search.Name);
//List.AddObject(Search.Na me, Bmp);
Index := List.Add(Bmp);
// Do something with Index...
ListBox1.Items.Add(Search. Name);
Error := FindNext(Search);
end;
FindClose(Search);
end;
//ListBox1.Items.AddString s(List);
end;
procedure TForm1.FormDestroy(Sender: TObject);
var
I: Integer;
begin
for I := 0 to List.Count - 1 do begin
//if assigned(List.Objects[I]) and (List.Objects[I] is TObject) then begin
//(List.Objects[I] as TObject).Free;
//end;
if assigned(List[I]) then TObject(List[I]).Free;
end;
end;
{procedure TForm1.ListBox1Click(Sende r: TObject);
var
I: Integer;
begin
I := List.IndexOf(ListBox1.Item s[ListBox1 .ItemIndex ]);
if (I >= 0) then begin
if assigned(List.Objects[I]) and (List.Objects[I] is TJPEGImage) then begin
Image1.Picture.Bitmap.Assi gn(List.Ob jects[I] as TJPEGImage);
end;
end;
end;
}
procedure TForm1.ListBox1Click(Sende r: TObject);
begin
if (ListBox1.ItemIndex < List.Count) then Image1.Picture.Bitmap.Assi gn(TGraphi c(List[Lis tBox1.Item Index]));
end;
end.
</code>
This sample demonstrates uning a TList. I use the TListbox just as a simple method to select an image. You might prefer to remember the index-number that the List.Add method return to you. Link that number to the associated compagny.
And about memory-size... This depends on the size of the images. I myself hardly notice any loss of speed, but I have 256 MB RDRAM which is quite a lot and very fast. (And a swapfile of around 700 MB...)
On a small 233 MHz PC with 64 MB RAM, you could end up with the images in your virtual memory, and thus some loss of speed. Increase the swapfile if required...
Still, you will only notice this if you have more megabytes of images than around a third of RAM. (So with 64 MB, less than 20 MB worth of images shouldn't be a big problem...)
<code>
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, JPeG, Psock, NMTime;
type
TForm1 = class(TForm)
ListBox1: TListBox;
Image1: TImage;
NMTime1: TNMTime;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
private
//List: TStringList;
List: TList;
public
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
const
Path = 'C:\Documents and Settings\Administrator.WIM
var
Search: TSearchRec;
Error: Integer;
Bmp: TJPEGImage;
begin
//List := TStringList.Create;
List := TList.Create;
Error := FindFirst(Path + '*.jpg', faAnyFile - faDirectory, Search);
if (Error = 0) then begin
while (Error = 0) do begin
Bmp := TJPEGImage.Create;
Bmp.LoadFromFile(Path + Search.Name);
//List.AddObject(Search.Na
Index := List.Add(Bmp);
// Do something with Index...
ListBox1.Items.Add(Search.
Error := FindNext(Search);
end;
FindClose(Search);
end;
//ListBox1.Items.AddString
end;
procedure TForm1.FormDestroy(Sender:
var
I: Integer;
begin
for I := 0 to List.Count - 1 do begin
//if assigned(List.Objects[I]) and (List.Objects[I] is TObject) then begin
//(List.Objects[I] as TObject).Free;
//end;
if assigned(List[I]) then TObject(List[I]).Free;
end;
end;
{procedure TForm1.ListBox1Click(Sende
var
I: Integer;
begin
I := List.IndexOf(ListBox1.Item
if (I >= 0) then begin
if assigned(List.Objects[I]) and (List.Objects[I] is TJPEGImage) then begin
Image1.Picture.Bitmap.Assi
end;
end;
end;
}
procedure TForm1.ListBox1Click(Sende
begin
if (ListBox1.ItemIndex < List.Count) then Image1.Picture.Bitmap.Assi
end;
end.
</code>
This sample demonstrates uning a TList. I use the TListbox just as a simple method to select an image. You might prefer to remember the index-number that the List.Add method return to you. Link that number to the associated compagny.
And about memory-size... This depends on the size of the images. I myself hardly notice any loss of speed, but I have 256 MB RDRAM which is quite a lot and very fast. (And a swapfile of around 700 MB...)
On a small 233 MHz PC with 64 MB RAM, you could end up with the images in your virtual memory, and thus some loss of speed. Increase the swapfile if required...
Still, you will only notice this if you have more megabytes of images than around a third of RAM. (So with 64 MB, less than 20 MB worth of images shouldn't be a big problem...)
@#$% Why does my answer appear twice??? :-(
ASKER
Hi Workshop_Alex,
This is what I have done.
//************************ ****//
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls, Db, DBTables, jpeg;
type
TForm1 = class(TForm)
Image1: TImage;
Button1: TButton;
Edit1: TEdit;
qrySystem1: TQuery;
Database1: TDatabase;
Button2: TButton;
ComboBox1: TComboBox;
Edit2: TEdit;
Edit3: TEdit;
procedure FormCreate(Sender: TObject);
procedure UpdateArray;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Reconnect;
procedure ComboBox1Change(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
BmpArray : array[1..20] of TJPegImage;
NewArray : array[1..40] of String;
ListArray : array[1..40,1..3] of String;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
const
Path = 'C:\Logos\bmp\';
var
Search: TSearchRec;
Error: Integer;
Bmp: TJPEGImage;
i : SmallInt;
begin
Reconnect; //Proc to Connect to DBASE
Error := FindFirst(Path + '*.jpg', faAnyFile - faDirectory, Search);
if (Error = 0) then
begin
i := 1;
while (Error = 0) do
begin
Bmp := TJPEGImage.Create;
Bmp.LoadFromFile(Path + Search.Name);
BmpArray[i] := Bmp;
NewArray[i] := Search.Name;
Error := FindNext(Search);
inc(i)
end;
FindClose(Search);
end;
end;
//Button 2 gets the data into the Combobox - (depending on the search)
procedure TForm1.Button2Click(Sender : TObject);
var
i,S : smallInt;
begin
qrySystem1.Close;
qrySystem1.SQL.Clear;
qrySystem1.SQL.Add('Select ClientName,ClientCode, LogoName from Client');
qrySystem1.Open;
qrySystem1.First;
ComboBox1.Clear;
for i := 1 to qrySystem1.RecordCount do
begin
ComboBox1.Items.Add(qrySys tem1.Field byname('Cl ientName') .asString + ' ' + qrySystem1.Fieldbyname('Lo goName').a sString);
ListArray[i][1] := qrySystem1.Fieldbyname('Lo goName').a sString;
qrySystem1.Next;
end;
UpdateArray;
end;
procedure TForm1.UpdateArray;
var
i, s : integer;
begin
for i := 1 to 40 do
begin
for s := 1 to 40 do
begin
if LowerCase(ListArray[s][1]) = NewArray[i] then
ListArray[s][2] := IntToStr(i)
end;
end;
end;
procedure TForm1.ComboBox1Change(Sen der: TObject);
var
Value : Integer;
Value1 : String;
begin
try
edit2.Text := ListArray[ComboBox1.ItemIn dex+1][1];
Value := StrToInt(ListArray[ComboBo x1.ItemInd ex+1][2]);
Image1.Picture.Assign(BmpA rray[Value ] as TJPegImage);
except
Showmessage('No Logo');
end;
end;
regards
TAZI
This is what I have done.
//************************
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls, Db, DBTables, jpeg;
type
TForm1 = class(TForm)
Image1: TImage;
Button1: TButton;
Edit1: TEdit;
qrySystem1: TQuery;
Database1: TDatabase;
Button2: TButton;
ComboBox1: TComboBox;
Edit2: TEdit;
Edit3: TEdit;
procedure FormCreate(Sender: TObject);
procedure UpdateArray;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Reconnect;
procedure ComboBox1Change(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
BmpArray : array[1..20] of TJPegImage;
NewArray : array[1..40] of String;
ListArray : array[1..40,1..3] of String;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
const
Path = 'C:\Logos\bmp\';
var
Search: TSearchRec;
Error: Integer;
Bmp: TJPEGImage;
i : SmallInt;
begin
Reconnect; //Proc to Connect to DBASE
Error := FindFirst(Path + '*.jpg', faAnyFile - faDirectory, Search);
if (Error = 0) then
begin
i := 1;
while (Error = 0) do
begin
Bmp := TJPEGImage.Create;
Bmp.LoadFromFile(Path + Search.Name);
BmpArray[i] := Bmp;
NewArray[i] := Search.Name;
Error := FindNext(Search);
inc(i)
end;
FindClose(Search);
end;
end;
//Button 2 gets the data into the Combobox - (depending on the search)
procedure TForm1.Button2Click(Sender
var
i,S : smallInt;
begin
qrySystem1.Close;
qrySystem1.SQL.Clear;
qrySystem1.SQL.Add('Select
qrySystem1.Open;
qrySystem1.First;
ComboBox1.Clear;
for i := 1 to qrySystem1.RecordCount do
begin
ComboBox1.Items.Add(qrySys
ListArray[i][1] := qrySystem1.Fieldbyname('Lo
qrySystem1.Next;
end;
UpdateArray;
end;
procedure TForm1.UpdateArray;
var
i, s : integer;
begin
for i := 1 to 40 do
begin
for s := 1 to 40 do
begin
if LowerCase(ListArray[s][1])
ListArray[s][2] := IntToStr(i)
end;
end;
end;
procedure TForm1.ComboBox1Change(Sen
var
Value : Integer;
Value1 : String;
begin
try
edit2.Text := ListArray[ComboBox1.ItemIn
Value := StrToInt(ListArray[ComboBo
Image1.Picture.Assign(BmpA
except
Showmessage('No Logo');
end;
end;
regards
TAZI
ASKER
Hi,
In your example above, you've got a statement as ffg.
Index := List.Add(Bmp);
Index is declared as what type ??
Regards
TAZI
In your example above, you've got a statement as ffg.
Index := List.Add(Bmp);
Index is declared as what type ??
Regards
TAZI
ASKER
Hi,
I have modified my code and I declare the arrays as
var
BMPArray : array of TJpegImages;
Laster, I declare the length of this array depending on the No of Images on my drive
SetLength(BMPArray,Value)
This dynamically creates the size of the array.
Regards
TAZI
I have modified my code and I declare the arrays as
var
BMPArray : array of TJpegImages;
Laster, I declare the length of this array depending on the No of Images on my drive
SetLength(BMPArray,Value)
This dynamically creates the size of the array.
Regards
TAZI
Index is defined as an Integer in the TForm1.FormCreate procedure. List.Add returns an Integer, so Index is an Integer.
You get a warning in my code, since I don't use Index after the assignment. For example, I don't link Index with some other data. You want to show a certain logo based on some condition, so you will need to know it's indexnumber in the list.
The advantage of using a TList in stead of an array is that the TList can hold any number of images, while the array has a fixed size. That's why I prefer a TList.
And in your case, where each logo has a name, I would prefer using a stringlist since this makes finding the right logo a bit easier...
But let's create another sample based on your code and let's use the database you've supplied... (For this, I've created a dummy table with some random data...) This sample will handle multiple image file formats!...
I also assume that the logonames in the database are the filenames of the logo files excluding the file extension! If not, then what relation does exists?
<DFM>
object Form1: TForm1
Left = 317
Top = 107
Width = 869
Height = 640
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
OnDestroy = FormDestroy
PixelsPerInch = 96
TextHeight = 13
object Splitter1: TSplitter
Left = 0
Top = 121
Width = 861
Height = 3
Cursor = crVSplit
Align = alTop
end
object ScrollBox1: TScrollBox
Left = 0
Top = 124
Width = 861
Height = 489
Align = alClient
BorderStyle = bsNone
TabOrder = 0
object Image1: TImage
Left = 0
Top = 0
Width = 100
Height = 100
AutoSize = True
end
end
object Panel1: TPanel
Left = 0
Top = 0
Width = 861
Height = 121
Align = alTop
BevelInner = bvLowered
BorderWidth = 4
Caption = ' '
TabOrder = 1
object DBGrid1: TDBGrid
Left = 6
Top = 6
Width = 849
Height = 109
Align = alClient
DataSource = DataSource1
TabOrder = 0
TitleFont.Charset = DEFAULT_CHARSET
TitleFont.Color = clWindowText
TitleFont.Height = -11
TitleFont.Name = 'MS Sans Serif'
TitleFont.Style = []
Columns = <
item
Expanded = False
FieldName = 'ClientName'
Visible = True
end
item
Expanded = False
FieldName = 'ClientCode'
Visible = True
end>
end
end
object QrySystem1: TQuery
AfterScroll = QrySystem1AfterScroll
DatabaseName = 'Logos'
SQL.Strings = (
'SELECT '
' ClientName,'
' ClientCode,'
' LogoName'
'FROM'
' Client'
'ORDER BY'
' ClientName')
Left = 264
Top = 40
object QrySystem1ClientName: TStringField
FieldName = 'ClientName'
Origin = 'LOGOS."Client.DB".ClientN ame'
end
object QrySystem1ClientCode: TStringField
FieldName = 'ClientCode'
Origin = 'LOGOS."Client.DB".ClientC ode'
Size = 4
end
object QrySystem1LogoName: TStringField
FieldName = 'LogoName'
Origin = 'LOGOS."Client.DB".LogoNam e'
Size = 255
end
end
object Database1: TDatabase
AliasName = 'BCDEMOS'
Connected = True
DatabaseName = 'Logos'
LoginPrompt = False
Params.Strings = (
'PATH=C:\Logos\Database'
'DEFAULT DRIVER=PARADOX'
'ENABLE BCD=FALSE')
SessionName = 'Default'
Left = 360
Top = 40
end
object DataSource1: TDataSource
DataSet = QrySystem1
Left = 152
Top = 40
end
end
</DFM>
<code>
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, JPeG, Db, DBTables, Grids, DBGrids;
type
TForm1 = class(TForm)
QrySystem1: TQuery;
Database1: TDatabase;
ScrollBox1: TScrollBox;
Image1: TImage;
Panel1: TPanel;
DBGrid1: TDBGrid;
DataSource1: TDataSource;
Splitter1: TSplitter;
QrySystem1ClientName: TStringField;
QrySystem1ClientCode: TStringField;
QrySystem1LogoName: TStringField;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure QrySystem1AfterScroll(Data Set: TDataSet);
private
List: TStringList;
public
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
const
Path = 'C:\Logos\bmp\';
var
Search: TSearchRec;
Error: Integer;
Bmp: TGraphic;
begin
List := TStringList.Create;
List.Sorted := True;
List.Duplicates := dupIgnore;
Error := FindFirst(Path + '*.*', faAnyFile - faDirectory, Search);
if (Error = 0) then begin
while (Error = 0) do begin
if (UpperCase(ExtractFileExt( Search.Nam e)) = '.JPG') then begin
Bmp := TJPEGImage.Create;
end
else if (UpperCase(ExtractFileExt( Search.Nam e)) = '.BMP') then begin
Bmp := TBitmap.Create;
end
else if (UpperCase(ExtractFileExt( Search.Nam e)) = '.ICO') then begin
Bmp := TIcon.Create;
end
else if (UpperCase(ExtractFileExt( Search.Nam e)) = '.WMF') then begin
Bmp := TMetafile.Create;
end
else begin
Bmp := nil;
end;
if (Bmp <> nil) then begin
Bmp.LoadFromFile(Path + Search.Name);
List.AddObject(ChangeFileE xt(Search. Name, ''), Bmp);
end;
Error := FindNext(Search);
end;
FindClose(Search);
end;
QrySystem1.Active := True;
end;
procedure TForm1.FormDestroy(Sender: TObject);
var
I: Integer;
begin
QrySystem1.Active := False;
for I := 0 to List.Count - 1 do begin
if assigned(List.Objects[I]) and (List.Objects[I] is TObject) then begin
(List.Objects[I] as TObject).Free;
end;
end;
end;
procedure TForm1.QrySystem1AfterScro ll(DataSet : TDataSet);
var
I: Integer;
begin
I := List.IndexOf(QrySystem1.Fi eldByName( 'LogoName' ).AsString );
if (I >= 0) and assigned(List.Objects[I]) and (List.Objects[I] is TGraphic) then begin
Image1.Picture.Graphic := (List.Objects[I] as TGraphic);
end
else begin
Image1.Picture.Graphic := Application.Icon;
end;
end;
end.
</code>
Some explanation...
In TForm1.FormCreate I create the imagelist as a stringlist. Since we need to remember the names of the logos, the stringlist is the most compact option. I sort the stringlist since the 'IndexOf' method of the stringlist is much faster if it's a sorted list. I'm going to ignore duplicate names. (This could happen if a logo exists as a JPeG and as a bitmap, both with the same name but different extensions.)
And since logos are added to the list by name only, I remove the file extension. By the way, the IndexOf routine is case insensitive! No need to worry about that!
At the end of this call, the query is opened. You don't want to do this before the list is created...
Another option would be to assign the AfterScroll event to the query AFTER the list is created. "QrySystem1.AfterScroll := QrySystem1AfterScroll;" This way, you can keep the query open in design-time. But then don't set the AfterScroll event in designtime.
In TForm1.FormDestroy I remove the complete list of images. No true rocket-science. Just free all objects in the list, then free the list. And beware, make sure the qquery is closed.
TForm1.QrySystem1AfterScro ll is an event that's connected to the AfterScroll event of the Query. This will always show the right logo for the current record. No need to do some complex stuff... If you go to a new record, the image will adjust itself... No image available? Then the application icon will be shown. A bit nicer than an exception. You could also show some other bitmap, just to show that no logo is available. Or assign nil to Image1.Picture.Graphic. Then it will be empty...
On my PC, this code is lightning fast. But that's because it's a extremely fast machine... ;-)
You get a warning in my code, since I don't use Index after the assignment. For example, I don't link Index with some other data. You want to show a certain logo based on some condition, so you will need to know it's indexnumber in the list.
The advantage of using a TList in stead of an array is that the TList can hold any number of images, while the array has a fixed size. That's why I prefer a TList.
And in your case, where each logo has a name, I would prefer using a stringlist since this makes finding the right logo a bit easier...
But let's create another sample based on your code and let's use the database you've supplied... (For this, I've created a dummy table with some random data...) This sample will handle multiple image file formats!...
I also assume that the logonames in the database are the filenames of the logo files excluding the file extension! If not, then what relation does exists?
<DFM>
object Form1: TForm1
Left = 317
Top = 107
Width = 869
Height = 640
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
OnDestroy = FormDestroy
PixelsPerInch = 96
TextHeight = 13
object Splitter1: TSplitter
Left = 0
Top = 121
Width = 861
Height = 3
Cursor = crVSplit
Align = alTop
end
object ScrollBox1: TScrollBox
Left = 0
Top = 124
Width = 861
Height = 489
Align = alClient
BorderStyle = bsNone
TabOrder = 0
object Image1: TImage
Left = 0
Top = 0
Width = 100
Height = 100
AutoSize = True
end
end
object Panel1: TPanel
Left = 0
Top = 0
Width = 861
Height = 121
Align = alTop
BevelInner = bvLowered
BorderWidth = 4
Caption = ' '
TabOrder = 1
object DBGrid1: TDBGrid
Left = 6
Top = 6
Width = 849
Height = 109
Align = alClient
DataSource = DataSource1
TabOrder = 0
TitleFont.Charset = DEFAULT_CHARSET
TitleFont.Color = clWindowText
TitleFont.Height = -11
TitleFont.Name = 'MS Sans Serif'
TitleFont.Style = []
Columns = <
item
Expanded = False
FieldName = 'ClientName'
Visible = True
end
item
Expanded = False
FieldName = 'ClientCode'
Visible = True
end>
end
end
object QrySystem1: TQuery
AfterScroll = QrySystem1AfterScroll
DatabaseName = 'Logos'
SQL.Strings = (
'SELECT '
' ClientName,'
' ClientCode,'
' LogoName'
'FROM'
' Client'
'ORDER BY'
' ClientName')
Left = 264
Top = 40
object QrySystem1ClientName: TStringField
FieldName = 'ClientName'
Origin = 'LOGOS."Client.DB".ClientN
end
object QrySystem1ClientCode: TStringField
FieldName = 'ClientCode'
Origin = 'LOGOS."Client.DB".ClientC
Size = 4
end
object QrySystem1LogoName: TStringField
FieldName = 'LogoName'
Origin = 'LOGOS."Client.DB".LogoNam
Size = 255
end
end
object Database1: TDatabase
AliasName = 'BCDEMOS'
Connected = True
DatabaseName = 'Logos'
LoginPrompt = False
Params.Strings = (
'PATH=C:\Logos\Database'
'DEFAULT DRIVER=PARADOX'
'ENABLE BCD=FALSE')
SessionName = 'Default'
Left = 360
Top = 40
end
object DataSource1: TDataSource
DataSet = QrySystem1
Left = 152
Top = 40
end
end
</DFM>
<code>
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, JPeG, Db, DBTables, Grids, DBGrids;
type
TForm1 = class(TForm)
QrySystem1: TQuery;
Database1: TDatabase;
ScrollBox1: TScrollBox;
Image1: TImage;
Panel1: TPanel;
DBGrid1: TDBGrid;
DataSource1: TDataSource;
Splitter1: TSplitter;
QrySystem1ClientName: TStringField;
QrySystem1ClientCode: TStringField;
QrySystem1LogoName: TStringField;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure QrySystem1AfterScroll(Data
private
List: TStringList;
public
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
const
Path = 'C:\Logos\bmp\';
var
Search: TSearchRec;
Error: Integer;
Bmp: TGraphic;
begin
List := TStringList.Create;
List.Sorted := True;
List.Duplicates := dupIgnore;
Error := FindFirst(Path + '*.*', faAnyFile - faDirectory, Search);
if (Error = 0) then begin
while (Error = 0) do begin
if (UpperCase(ExtractFileExt(
Bmp := TJPEGImage.Create;
end
else if (UpperCase(ExtractFileExt(
Bmp := TBitmap.Create;
end
else if (UpperCase(ExtractFileExt(
Bmp := TIcon.Create;
end
else if (UpperCase(ExtractFileExt(
Bmp := TMetafile.Create;
end
else begin
Bmp := nil;
end;
if (Bmp <> nil) then begin
Bmp.LoadFromFile(Path + Search.Name);
List.AddObject(ChangeFileE
end;
Error := FindNext(Search);
end;
FindClose(Search);
end;
QrySystem1.Active := True;
end;
procedure TForm1.FormDestroy(Sender:
var
I: Integer;
begin
QrySystem1.Active := False;
for I := 0 to List.Count - 1 do begin
if assigned(List.Objects[I]) and (List.Objects[I] is TObject) then begin
(List.Objects[I] as TObject).Free;
end;
end;
end;
procedure TForm1.QrySystem1AfterScro
var
I: Integer;
begin
I := List.IndexOf(QrySystem1.Fi
if (I >= 0) and assigned(List.Objects[I]) and (List.Objects[I] is TGraphic) then begin
Image1.Picture.Graphic := (List.Objects[I] as TGraphic);
end
else begin
Image1.Picture.Graphic := Application.Icon;
end;
end;
end.
</code>
Some explanation...
In TForm1.FormCreate I create the imagelist as a stringlist. Since we need to remember the names of the logos, the stringlist is the most compact option. I sort the stringlist since the 'IndexOf' method of the stringlist is much faster if it's a sorted list. I'm going to ignore duplicate names. (This could happen if a logo exists as a JPeG and as a bitmap, both with the same name but different extensions.)
And since logos are added to the list by name only, I remove the file extension. By the way, the IndexOf routine is case insensitive! No need to worry about that!
At the end of this call, the query is opened. You don't want to do this before the list is created...
Another option would be to assign the AfterScroll event to the query AFTER the list is created. "QrySystem1.AfterScroll := QrySystem1AfterScroll;" This way, you can keep the query open in design-time. But then don't set the AfterScroll event in designtime.
In TForm1.FormDestroy I remove the complete list of images. No true rocket-science. Just free all objects in the list, then free the list. And beware, make sure the qquery is closed.
TForm1.QrySystem1AfterScro
On my PC, this code is lightning fast. But that's because it's a extremely fast machine... ;-)
First you insert a form a filelistbox and image. and you should write this codes :
{event of the filelistbox click}
procedure TForm1.FileListBox1Change( Sender: TObject);
begin
image1.Picture.Bitmap.Load FromFile(f ilelistbox 1.filename );
end;
{event of the filelistbox click}
procedure TForm1.FileListBox1Change(
begin
image1.Picture.Bitmap.Load
end;
undefinity, didn't you read the question correctly? The problem is that loading the image when it's required is too slow. The user is browsing through multiple records, and thus multiple logo's. The logo's aren't part of the database, but loose images in a folder on a network-drive. Every time they're loaded it takes some time. This slows down the browsing to an unacceptable level.
So, the solution so far is to load the images at startup and then access them from memory. This costs a lot of internal memory (RAM & swapfile) but it's quicker to browse through than reloading the different images every time.
Speed is important in this case...
So, the solution so far is to load the images at startup and then access them from memory. This costs a lot of internal memory (RAM & swapfile) but it's quicker to browse through than reloading the different images every time.
Speed is important in this case...
Additionally, it is very unfriendly to propose an answer instead of a comment when we are already discussing the problem quite a while.
Ciao, Mike
Ciao, Mike
ASKER
Hi,
Lischke, Workshop_Alex & undefinity
To - undefinity : Workshop_Alex explains the problem above.
Guys, thanks for your efforts. Give me a couple of days to get the entire code tested and functional
Many thanks for all your efforts ... it is greatly appreciated
Lischke, Workshop_Alex & undefinity
To - undefinity : Workshop_Alex explains the problem above.
Guys, thanks for your efforts. Give me a couple of days to get the entire code tested and functional
Many thanks for all your efforts ... it is greatly appreciated
ASKER
Hi
Sorry about the long delay in responding to this question. I had actually forgotten about it until receiving an autodelete warning this morning.
Sorry about that ! !
I haven't yet implemented it into my program, but I have tried and tested it on a seperate application.
Thanks for all your efforts. It is greatly appreciated
Regards
TAZI
Sorry about the long delay in responding to this question. I had actually forgotten about it until receiving an autodelete warning this morning.
Sorry about that ! !
I haven't yet implemented it into my program, but I have tried and tested it on a seperate application.
Thanks for all your efforts. It is greatly appreciated
Regards
TAZI
Doesn't matter... I've forgotten about it too... ;-)
Thanx for the points!
Thanx for the points!
you have actually several options. You can store images onto disc or in the resouce of the executable. You can then load them into an image list (but this limits all images to the same size) or into a TBitmap.
For imagelists you can use TCustomImageList.FileLoad.
What do you prefer?
Ciao, Mike