Disable scrolling possibility of TWebBrowser - delphi

Does anyone know, how to disable scrolling possibility of TWebBrowser control in a Firemonkey iOS / Android application? My goal is to get absolutely static element that will not react on touches and so on.

There is no single setting or action that disables all user actions of the Fmx.TWebBrowser. But there is a feature you can use for your purpose.
The feature I refer to, is Fmx.WebBrowser.TCustomWebBrowser.CaptureBitmap documented here
Description
Captures the currently visible Web page as a bitmap.
This method returns a TBitmap object, which allows you to create,
manipulate and store images in memory or as files on a disk. The
scenario of the use of this method could be as follows:
1. Call this method to capture a visible Web page as a bitmap.
2. Hide a TWebBrowser control.
3. Display the bitmap and overlay other components (such as buttons or popups) on top of the bitmap.
In your case you would just hide the WB and display the bitmap.
Tested with the following code:
type
TForm25 = class(TForm)
Button1: TButton;
WebBrowser1: TWebBrowser;
Edit1: TEdit;
Image1: TImage;
Timer1: TTimer;
procedure Button1Click(Sender: TObject);
procedure WebBrowser1DidFinishLoad(ASender: TObject);
procedure Timer1Timer(Sender: TObject);
private
{ Private declarations }
bmp: TBitmap;
public
{ Public declarations }
end;
implementation
procedure TForm25.Button1Click(Sender: TObject);
begin
WebBrowser1.URL := Edit1.Text;
end;
procedure TForm25.Timer1Timer(Sender: TObject);
begin
bmp := WebBrowser1.CaptureBitmap;
Image1.Bitmap := bmp;
end;
procedure TForm25.WebBrowser1DidFinishLoad(ASender: TObject);
begin
Timer1.Enabled := True;
end;
With the WB hidden, it cannot be operated on.
The timer (1000 ms) I added because my attempts to capture the image already in the OnDidFinishLoad() event did nöt succeed.

Related

Setfocus to the searchbox in a tlistview

I am working in Seattle, writing a FM application for windows only.
I have A tlistview on my form and have it populated with data.
I have the search option turned on.
How do I programmatically set focus to the search box?
How do I increase the size and font size of the search box?
thanks
The searchbox is not intended to be accessed programmatically except for setting it visible and to fire event when changed. Otherwise it is intended to be accessed only by the user.
Therefore, access is a little bit involved. However, the example of the OnSearchChange event inspired the following answer:
uses ..., FMX.SearchBox;
type
TForm17 = class(TForm)
ListView1: TListView;
Button1: TButton;
Label1: TLabel;
...
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
sb: TSearchBox; // a local reference
...
end;
implementation
procedure TForm17.Button1Click(Sender: TObject);
begin
if Assigned(sb) then
sb.SetFocus;
end;
procedure TForm17.FormCreate(Sender: TObject);
var
i: integer;
begin
ListView1.SearchVisible := True; // or set in the Object Inspector at design time
for i := 0 to ListView1.Controls.Count-1 do
if ListView1.Controls[I].ClassType = TSearchBox then
begin
sb := TSearchBox(ListView1.Controls[i]);
Break;
end;
end;
procedure TForm17.ListView1SearchChange(Sender: TObject);
begin
if Assigned(sb) then
Label1.Text := sb.Text;
end;
At form creation we search the SearchBox control and if found we store a reference to it in the sb: TSearchBox; field. Then access is quite straightforward.

Delphi Panels and custom component Z order issue

I'm working on a personal project and I have been running into lots of issues lately resulting in many questions, but hey, thats what SO is for right? ;)
Anyhow I tried making a transparent TPanel which I achieved by making a custom component.
The app im making is about world of warcraft and I made a talent calculator like on the official website but in a windows application.
Talents are spells/skills and each talent has information which is displayed in a tooltip.
So I have a tooltip with info,
I have a grid with talents and when I hover on a talent I want to see the info.
Besides that, I want the info to be shown near the position of the cursor.
Almost works. The positioning works, it shows the correct info BUT! here is the problem.
Take a look at this image:
The black semi-transparent panel is my tooltip.
You see the talents (that little 4x6 grid) those are located in a dark grey panel called pnlTalents
The parent of that panel is the lighter grey panel that covers the entire form called Panel1.
The tooltip called TooltipTalent also has the parent Panel1.
I have tried sending pnlTalents to the back and bring TooltipTalent to the front but this made no difference at all.
I even tried TooltipTalent.BringToFront; the moment the position is changed.
Notice how the tooltip has no problem being on top of that darker grey panel at the top of the screen with the speedbuttons.
I compared both panels (the one at the top and the one with the talents) and found no difference in the properties.
I am seriously running out of ideas here. I have no clue what is causing it and how I can solve this problem.
As last resort I tried dropping another transparent panel that covers the entire form to see if that would help but the problem still persisted.
I could also post the code of my custom component but that would be a lot.
If you want to see the code let me know and i'll find a way to show it :)
Can anyone help me on this?
Kind regards
procedure TMyPanel.CreateParams(var params: TCreateParams);
begin
params.ExStyle := params.ExStyle or WS_EX_TRANSPARENT or WS_EX_TOPMOST ;
inherited CreateParams(params);
end;
With a Quickhackcode I get this result
Just as example, Image1 contains a Semitransparent png:
unit Unit4;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, dxGDIPlusClasses;
type
TMyPanel=Class(TPanel)
procedure CreateParams(var params: TCreateParams); override;
procedure WMEraseBkGnd(var msg: TWMEraseBkGnd); message WM_ERASEBKGND;
End;
TForm4 = class(TForm)
Panel1: TPanel;
Button1: TButton;
Image1: TImage;
Button2: TButton;
CheckBox1: TCheckBox;
Panel2: TPanel;
Button3: TButton;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private-Deklarationen }
Fmp:TMyPanel;
fisInPaint:Boolean;
public
{ Public-Deklarationen }
end;
var
Form4: TForm4;
implementation
{$R *.dfm}
{ TMyPanel }
procedure TMyPanel.CreateParams(var params: TCreateParams);
begin
params.ExStyle := params.ExStyle or WS_EX_TRANSPARENT or WS_EX_TOPMOST ;
inherited CreateParams(params);
end;
procedure TMyPanel.WMEraseBkGnd(var msg: TWMEraseBkGnd);
begin
SetBkMode (msg.DC, TRANSPARENT);
msg.result := 1;
end;
procedure TForm4.Button1Click(Sender: TObject);
begin
Fmp := TMyPanel.Create(self);
With Fmp do
begin
Parent := self;
left:= Panel1.Left -100;
top:= Panel1.top -100;
width := 300;
Height := 300;
end;
image1.Parent := Fmp;
Image1.Align := alClient;
Image1.Stretch := true;
Fmp.BringToFront;
Label1.Parent := FMP;
label1.Transparent := true;
Label1.Left := 100;
Label1.Left := 100;
end;
procedure TForm4.Button3Click(Sender: TObject);
begin
Fmp.Left := fmp.Left + 10;
end;
end.
Can't reproduce problem with XP either:

how to calculate the Framerate and Timecode during screen capturing?

Delphi 6 project
I have searched google pretty thorough but am not finding the answers to my delima. basically i want to have the timecode and videos framerate of a current screen capture session showing in my app, in the statusbar or label. i also need this with respect to syncing the captures to the framerate of the sofware player playing the video, otherwise i get a lot of duplicate or missed frames. the videos are 29.970 and 23.976 fps. So i need to be able to configure for both, somehow.
Currently, I can screen capture from tv cards and software video players like, vlc, ffplay, mplayer, virtualdub, etc.
i'm not sure how to implement the necessary routines into mine, let alone where. i've been reading a lot about the following items below but they are all over my head though i did make many attempts at it:
timer1 control -- setting interval to 34 is not exact, it duplicates or misses frames during screen capture
gettimetick and timegettime
timeBeginPeriod and timeEndPeriod
QueryPerformanceTimer and QueryPerformanceCounter
To help simiplfy the process, i snipped a lot of code of the original project to only feature the screen capturing. Here is the complete routine (along with some remarked-out experimental code) for this:
(thanks in advanced for any help)
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, mmsystem,
ExtCtrls, clipbrd, DXClass;
type
TForm1 = class(TForm)
Timer1: TTimer;
Panel1: TPanel;
m1: TMemo;
btnCapOnOff: TButton;
txtHandle: TEdit;
Edit2: TEdit;
stDataRate: TStaticText;
btnCopy: TButton;
btnSetHDC: TButton;
dxt1: TDXTimer;
sb1: TScrollBox;
Splitter1: TSplitter;
im1: TImage;
procedure btnCapOnOffClick(Sender: TObject);
procedure FormActivate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure capturewindow;
procedure Timer1Timer(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure btnCopyClick(Sender: TObject);
procedure btnSetHDCClick(Sender: TObject);
procedure dxt1Timer(Sender: TObject; LagCount: Integer);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
start,
finish : cardinal; //int64;
i : integer;
s : string;
bm: tbitmap;
dc: hdc=0;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
form1.DoubleBuffered:=true;
sb1.DoubleBuffered:=true; // this is a scrollbox control
end;
procedure TForm1.FormActivate(Sender: TObject);
begin
im1.Picture.Bitmap.PixelFormat:=pf24bit;
im1.Width:=352;
im1.Height:=240;
end;
procedure TForm1.btnSetHDCClick(Sender: TObject);
begin
if dc=0 then dc := getdc(strToint(txtHandle.text));
end;
procedure TForm1.capturewindow;
begin
//timeBeginPeriod(1);
start := timegettime;
//sleep(1);
bitblt(bm.canvas.Handle, 0,0, 352,240, dc, 0,0, srccopy);
finish := timegettime-start;
//m1.lines.Add(intTostr(finish)); // debugging: to spill out timing values, etc.
im1.Picture.Bitmap := bm;
stDataRate.Caption := 'Date Rate: '+intTostr(finish) + ' fps or ms';
end;
procedure TForm1.dxt1Timer(Sender: TObject; LagCount: Integer);
begin
capturewindow;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
// capturewindow; // timer1 is too slow or unpredictable
end;
// button: a cheeters way to turn On or Off capturing
procedure TForm1.btnCapOnOffClick(Sender: TObject);
begin
if btnCapOnOff.caption='Cap is Off' then begin
btnCapOnOff.caption:='Cap is On';
//timer1.Enabled:=true; // capture the window // too slow
dxt1.Enabled:=true; // capture the window // a better timer control component (delphiX)
end else begin
btnCapOnOff.Caption:='Cap is Off';
//timer1.Enabled:=false; // too slow
dxt1.Enabled:=false; // stop capturing the window // a better timer control component (delphiX)
end;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
bm.free;
releaseDC(dc,dc);
//timeEndPeriod(1);
end;
procedure TForm1.btnCopyClick(Sender: TObject);
begin
clipboard.assign(im1.picture.bitmap); // to take quick pics
end;
initialization
bm := tbitmap.Create;
bm.PixelFormat:=pf24bit;
bm.Width:=352;
bm.Height:=240; beep;
end.
Actually hooking the software that's playing the video, and synchronizing to it, I'm not sure how to do that. But working on timing might help out. Assuming that the software playing the video is also well timed, you should be able to get a smooth capture.
This tutorial is useful: http://www.codeproject.com/Articles/1236/Timers-Tutorial
The "Multimedia Timers" offer good resolution (down to 1ms on most machines), and I've found them to be reliable.
What I would try is using the Performance Timer (queryperformancetimer, as you've already mentioned) to time your "CaptureWindow" procedure. Then, when you call "timesetevent" in a multimedia timer, subtract the amount of time the capture took from the overall time of a single frame, and use that as your "uDelay" value.
HowLongTimerShouldWait := LengthOfASingleFrame - TimeSpentCapturingPreviousFrame
The nice thing about the Multimedia Timers is that they let you use it as a 'one shot', where each interval can have a different delay period. I've generally set the timer to call a single procedure recursively, until it's flagged to stop.
This way, with a bit of fine tuning, you should be able to get capture rates are are within a +/-1ms tolerance of the actual video FPS.
As promised, here is the code i came up with based on some google searches and working them out in delphi. the following links did help me out some though (but due to c/c++/c# i could not translate as easily to delphi) so most of the final answer were based on lots of trial and error:
http://www.andrewduncan.ws/Timecodes/Timecodes.html
http://puredata.hurleur.com/sujet-990-framenumber-timecode-conversion
To my knowledge the routine works flawless. but just so you know, i like my numbers formated for spacing purposes, so i padded to 2-digits, this way there is not shriking back and forth as numbers progress past 59.
Heres how it works:
It computes the timecode based on the frame rate of your video source (ie 29.970 interlace or progressive, and 23.976 for 24p film) .. so just feed it a frame number and the function will return the timecode in string format.
Example Preporation/Useage:
put two Tedit's and one Tbutton control on your form1
in button1 onClick event, enter this: edit2.text := frameNo2timecode(strToint(edit1.text), 29.970);
now, run the program and enter your frame number in the first edit1.text
then, press the button1 control, it will compute the timecode in edit2.text
source code to calculate timecode:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, math;
type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function FrameNo2Timecode(fn: longint; rate: real): string;
var
hours,mins,secs,milli: extended;
hoursStr, minsStr, secsStr, milliStr: string;
function padzero(N: longint; Len: Integer): string;
begin
FmtStr(Result, '%d', [N]);
while Length(Result) < Len do
Result := '0' + Result;
end;
begin
hours := floor( (fn/rate)/3600) mod 60;
hoursStr := padzero(floor(hours),2);
mins := floor( (fn/rate)/60.0) mod 60;
minsstr := padzero(floor(mins),2);
secs := floor( (fn/rate)) mod 60;
secsstr := padzero(floor(secs),2);
milli := floor( (1000*fn/rate)) mod 6000 mod 1000;
millistr := padzero(floor(milli),3);
result := hoursStr +':'+ minsStr +':'+ secsStr +'.'+ milliStr;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
edit2.text := frameNo2timecode(strToint(edit1.text), 29.970);
end;
end.

Delphi 2010 - How to Copy and Clear the TShape

Ok, after working with TShape, I need to clean my "Shape1" from Lines and Text.
And also how to copy everything in "Shape1" into "Shape2" ?
Thanks B4 ^o^
type
TShape = class(ExtCtrls.TShape); //interposer class
TForm1 = class(TForm)
Shape1: TShape;
Shape2: TShape;
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
public
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
// Draw some text on Shape1 := TShape
Shape1.Canvas.Font.Name :='Arial';// set the font
Shape1.Canvas.Font.Size :=20;//set the size of the font
Shape1.Canvas.Font.Color:=clBlue;//set the color of the text
Shape1.Canvas.TextOut(10,10,'1999');
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
// Copy everything from Shape1 to Shape2 (make a duplication)
// How to do it ?
showmessage('copy Shape1 into Shape2');
end;
End.
Following pseudo-code makes a copy of SourceShape canvas content to the TargetShape canvas, but only until the TargetShape is refreshed:
procedure TForm1.Button1Click(Sender: TObject);
begin
TargetShape.Canvas.CopyRect(Rect(0, 0, TargetShape.ClientWidth,
TargetShape.ClientHeight), SourceShape.Canvas, Rect(0, 0,
SourceShape.ClientWidth, SourceShape.ClientHeight));
end;
To clear the previously copied content, you can use the following:
procedure TForm1.Button2Click(Sender: TObject);
begin
TargetShape.Invalidate;
end;
To keep your drawing persistent you need to implement your own OnPaint event, in which whenever it fires, copy the current canvas content from the source to target using the CopyRect method like shown above.
But the question is then, why to use a TShape control at all. It would be better to use TPaintBox and draw your stuff by yourself including the shapes that are drawn by TShape control.

Frames and Browse History in Delphi

I am currently developing a delphi application that will need a browse history and am trying to work out how exactly to implement this.
The application has 2 modes. Browse and Details. Both designed as Frames.
After a search an appropriate number of Browse Frames are created in Panel 1 and populated.
From a Browse Frame we can either open the Detail Frame, replacing the contents of Panel 1 with the contents of the Detail Frame. Alternatively a new search can be spawned, replacing the current set of results with a new set.
From the Detail Frame we can either edit details, or spawn new searches. Certain searches are only available from the Detail Frame. Others from either the Browse Frames or the Detail Frame.
Each time a user displays the Detail Frame, or spawns a new search I want to record that action and be able to repeat it. Other actions like edits or "more details" won't be recorded. (Obviously if a user goes back a few steps then heads down a different search path this will start the history fresh from this point)
In my mind I want to record the procedure calls that were made in a list e.g.
SearchByName(Search.Text);
SearchByName(ArchName.Text);
DisplayDetails(JobID);
SearchByName(EngineerName.Text);
DisplayDetails(JobID);
Then I can just (somehow) call each item in order as I go bak and forward...
In response to Dan Kelly's request to store the function:
However what I still can't see is how I call the stored function -
What you are referring to is storing a method handler. The code below demonstrates this. But, as you indicated your self, you could do a big if..then or case statement.
This all will works. But an even more "eloquent" way of doing all this is to store object pointers. For example, if a search opens another search, you pass a pointer of the first to the 2nd. Then in the 2nd if you want to refer back to it, you have a pointer to it (first check that it is not nil/free). This is a much more object oriented approach and would lend itself better to situations where someone might close one of the frames out of sequence.
unit searchit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TSearchObject = class
FSearchValue: String;
FOnEventClick: TNotifyEvent;
constructor Create(mSearchValue: string; mOnEventClick: TNotifyEvent);
procedure FireItsEvent;
end;
type
TForm1 = class(TForm)
SearchByName: TButton;
GoBack: TButton;
DisplayDetails: TButton;
searchfield: TEdit;
jobid: TEdit;
procedure FormCreate(Sender: TObject);
procedure SearchByNameClick(Sender: TObject);
procedure GoBackClick(Sender: TObject);
procedure DisplayDetailsClick(Sender: TObject);
private
{ Private declarations }
SearchObjectsList: TStringList;
procedure DisplayDetailFunction(Sender: TObject);
procedure SearchByNameFunction(Sender: TObject);
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
constructor TSearchObject.Create(mSearchValue: string;mOnEventClick: TNotifyEvent);
begin
FOnEventClick := mOnEventClick;
FSearchValue := mSearchValue;
end;
{$R *.dfm}
procedure TSearchObject.FireItsEvent;
begin
if Assigned(FOnEventClick) then
FOnEventClick(self);
end;
procedure TForm1.SearchByNameClick(Sender: TObject);
var
mSearchObject: TSearchObject;
begin
mSearchObject := TSearchObject.Create(SearchField.Text,SearchByNameFunction);
SearchObjectsList.AddObject(SearchField.Text,mSearchObject);
end;
procedure TForm1.DisplayDetailFunction(Sender: TObject);
var
mSearchObject: TSearchObject;
begin
mSearchObject := TSearchObject(Sender);
ShowMessage('This is the Display Detail Event. The value of the JobID is '+mSearchObject.FSearchValue);
end;
procedure TForm1.SearchByNameFunction(Sender: TObject);
var
mSearchObject: TSearchObject;
begin
mSearchObject := TSearchObject(Sender);
ShowMessage('This is the SearchByName Event. The value of the Search Field is '+mSearchObject.FSearchValue);
end;
procedure TForm1.DisplayDetailsClick(Sender: TObject);
var
mSearchObject: TSearchObject;
begin
mSearchObject := TSearchObject.Create(jobid.text,DisplayDetailFunction);
SearchObjectsList.AddObject(jobid.text,mSearchObject);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
SearchObjectsList := TStringList.Create;
end;
procedure TForm1.GoBackClick(Sender: TObject);
var
mSearchObject: TSearchObject;
begin
if SearchObjectsList.count=0 then
showmessage('Cannot go Back!')
else begin
mSearchObject := TSearchObject(SearchObjectsList.Objects[SearchObjectsList.count-1]);
mSearchObject.FireItsEvent;
SearchObjectsList.Delete(SearchObjectsList.count-1);
end;
end;
end.
Keep track of everything in a TStringList; when they go "Back" you delete from the string list. This is a sort of prototype:
type
TSearchObject = class
FSearchFunction,FSearchValue: String;
constructor Create(mSearchFunction,mSearchValue: string);
end;
type
TForm1 = class(TForm)
SearchByName: TButton;
GoBack: TButton;
DisplayDetails: TButton;
searchfield: TEdit;
procedure FormCreate(Sender: TObject);
procedure SearchByNameClick(Sender: TObject);
procedure GoBackClick(Sender: TObject);
procedure DisplayDetailsClick(Sender: TObject);
private
{ Private declarations }
SearchObjectsList: TStringList;
jobid: String; //not sure how you get this
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
constructor TSearchObject.Create(mSearchFunction,mSearchValue: string);
begin
FSearchFunction := mSearchFunction;
FSearchValue := mSearchValue;
end;
{$R *.dfm}
procedure TForm1.SearchByNameClick(Sender: TObject);
var
mSearchObject: TSearchObject;
begin
mSearchObject := TSearchObject.Create('SearchByName',SearchField.Text);
SearchObjectsList.AddObject(SearchField.Text,mSearchObject);
end;
procedure TForm1.DisplayDetailsClick(Sender: TObject);
var
mSearchObject: TSearchObject;
begin
mSearchObject := TSearchObject.Create('DisplayDetails',JobID);
SearchObjectsList.AddObject(JobId,mSearchObject);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
SearchObjectsList := TStringList.Create;
end;
procedure TForm1.GoBackClick(Sender: TObject);
var
mSearchObject: TSearchObject;
begin
if SearchObjectsList.count=0 then
showmessage('Cannot go Back!')
else begin
mSearchObject := TSearchObject(SearchObjectsList.Objects[SearchObjectsList.count-1]);
if mSearchObject.FSearchFunction ='SearchByName' then
ShowMessage('Value of Search Field:'+mSearchObject.FSearchValue)
else
ShowMessage('Value of JobID:'+mSearchObject.FSearchValue);
SearchObjectsList.Delete(SearchObjectsList.count-1);
end;
end;
Another option would be to use my wizard framework, which does this with TForms but can easily also be adjusted to use frames. The concept is that each summary form knows how to create its appropriate details. In your case the framework is more of an example of how to do it, rather than a plug and play solution.
Complementing MSchenkel answer.
To persist the list between program runs, use an ini file.
Here is the idea. You have to adapt it. Specially, you have to figure out the way to convert object to string and string to object, sketched here as ObjectToString(), StringToStringID and StringToObject().
At OnClose event, write the list out to the ini file.
const
IniFileName = 'MYPROG.INI';
MaxPersistedObjects = 10;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
ini: TIniFile;
i: integer;
cnt: integer;
begin
ini:=TIniFile.Create(iniFileName);
cnt:=SearchObjectsList.Count;
if cnt>MaxPersistedObjects then
cnt:=MaxPersistedObjects;
for i:=1 to MaxPersistedObjects do
if i>cnt then
ini.WriteString('SearchObjects','SearchObject'+intToStr(i),'');
else
ini.WriteString('SearchObjects','SearchObject'+intToStr(i),
ObjectToString(SearchObjectsList[i-1],SearchObjectsList.Objects[i-1]) );
ini.Free;
end;
and read it back at OnCreate event.
procedure TForm1.FormCreate(Sender: TObject);
var
ini: TIniFile;
i: integer;
begin
SearchObjectsList := TStringList.Create;
ini:=TIniFile.Create(IniFileName);
for i:=1 to MaxPersistedObjects do
begin
s:=ini.ReadString('SearchObjects','SearchObject'+intToStr(i),'');
if s<>'' then
SearchObjectsList.AddObject(StringToID(s),StringToObject(s));
end;
ini.Free;
end;

Resources