detect usb drive/device using delphi - delphi

i can't figure out the formatting rules here .. too many lines of code in my example to add 4 spaces to each line, so here is the link to the code i need help with
http://nitemsg.blogspot.com/2011/01/heres-unit-written-in-delphi-7-that-you.html
The problem I have is that I don't know enough about delphi to use this code with a form.
I am a drag and drop programmer only.
An example with a showmessage('friendly name =' + ... ) when a USB device is detected is what I need.
cheers,

If you are only familiar with drag-and-drop programming, and don't know much about objects or other units, then you need to get yourself familiarized with using objects other than auto-created forms and the components you drop in them.
The code at this link is an entire unit. You need to create a new Unit in your project (File > New > Unit). It will look something like this:
unit Unit1;
interface
implementation
end.
Now when you save the unit, the name of the unit will automatically change to the filename (without the extension) like this:
unit MahUSB;
interface
implementation
end.
In this example, you should use the same unit name as that source you're trying to use. Save the unit as 'MahUSB.pas', and should be in the same folder as the rest of your project (or elsewhere, just a suggestion). Copy/Paste all the code from that website and replace everything in this unit now.
Now in order to actually use this, you need to create an instance of this object. ONLY ONE INSTANCE (I say that just because by the looks of this, there's no need for more than one).
Very important: Seeing as you are not familiar with objects, let me quickly explain something. Objects need to be created in order to work. At the same time, anything that's created also needs to be free'd when you're done with it. In this case, we will create this object when your application starts, and free the object when your application closes.
Now on your MAIN FORM (not any other forms) you need to put an event handler for both OnCreate and OnDestroy. You also need to declare a variable to represent this object. In the declaration of your main form, add a variable 'USB' with the type of this object. Make sure that goes under the 'private' or 'public' section, either one is ok. Also make sure you declare the "MahUSB" unit at the top of your main unit in the uses clause.
Declaring the object in your main form:
type
TForm1 = class(TForm)
private
USB: TUsbClass;
public
end;
Creating/freeing object when your app starts/closes:
procedure TForm1.FormCreate(Sender: TObject);
begin
USB:= TUsbClass.Create;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
if assigned(USB) then USB.Free;
end;
Now we're not done yet. Now we need to add the event handlers. Notice at the top of this unit you got, there are two types called TOnDevVolumeEvent and TOnUsbChangeEvent. These are event types. The parameters in the event handlers must be identical to the parameters declared in these types. So now in your main form, declare these event handler procedures...
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
USB: TUsbClass;
procedure VolumeEvent(const bInserted : boolean; const sDrive : string);
procedure ChangeEvent(const bInserted : boolean;
const ADevType,ADriverName, AFriendlyName : string);
public
end;
Now just one more thing we have to do before this will work. The USB object needs to know what event handlers to use, therefore, we need to assign these procedures to the events. Upon your form's creation, we need to assign these events...
procedure TForm1.FormCreate(Sender: TObject);
begin
USB:= TUsbClass.Create;
USB.OnUsbChange:= Self.ChangeEvent;
USB.OnDevVolume:= Self.VolumeEvent;
end;
When all is said and done, your main form unit should look something like this:
unit uUSBTest;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, MahUSB;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
USB: TUsbClass;
procedure VolumeEvent(const bInserted : boolean; const sDrive : string);
procedure ChangeEvent(const bInserted : boolean;
const ADevType,ADriverName, AFriendlyName : string);
public
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.ChangeEvent(const bInserted: boolean; const ADevType,
ADriverName, AFriendlyName: string);
begin
ShowMessage('Change event for "'+AFriendlyName+'"');
end;
procedure TForm1.VolumeEvent(const bInserted: boolean;
const sDrive: string);
begin
ShowMessage('Volume event for "'+sDrive+'\"');
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
USB:= TUsbClass.Create;
USB.OnUsbChange:= Self.ChangeEvent;
USB.OnDevVolume:= Self.VolumeEvent;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
if assigned(USB) then USB.Free;
end;
end.
And there you are! You will have these two event handler procedures where you can further handle either of those two events.

Related

Delphi Using unit procedure on form

I'm learning OOP and I have created a basic program so far. I have create my own clas:
Type
Zombie = class
private
fLife : Integer;
fAge : Integer;
fHeight: String;
public
Constructor Create(pLife, pAge : Integer; pHeight : String);
Procedure SetLife(pLife : Integer);
function GetLife : Integer;
Procedure ShowLife;
end;
The procedure ShowLife does exactly what it says:
procedure Zombie.ShowLife;
begin
ShowMessage(inttostr(fLife));
end;
I'm trying to call this procedure on a Form but it says undeclared identifier:
procedure Tform1.ShowLifebtnClick(Sender: TObject);
begin
Zombies_Unit.ShowLife;
end;
I have included the unit in the user of the Form. How can I use methods on another form
You need to create and free the object before/after you use it. The pattern is like this:
MyZombie := TZombie.Create(10, 20, 30);
try
MyZombie.ShowLife();
finally
MyZombie.Free();
end;
You have to create an instance of your class and call the method of that object like
MyZombie := Zombie.create(20,15);
MyZombie.ShowLife;
...
MyZombie.free;
Sending from mobile, cannot format code.
EDIT/SUPPLEMENT:
As my short answer seems to be suitable to tech bad habits (I am sorry for that) I want to add the following advices to the asker:
Please use Try/Finally constructs to avoid that objects are not removed in case of an error occuring between create() and free() like Zdravko Danev's answer points out. It also makes sense to use common naming conventions to make your code easier to understand (e.g. TZombie as class name).
You must pay attention in one thing: Your class is in the same file of your form? If the answer is no, you must declare the unit name on uses of your form file like:
unit MyUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TMyForm = class(TForm)
private
{ Private declarations }
public
{ Public declarations }
end;
var
MyForm: TMyForm;
implementation
uses unitzombie; //The name unit where is your class
{$R *.dfm}
end.
After solving this little problem, you must create your object before calling this methods:
procedure Tform1.ShowLifebtnClick(Sender: TObject);
var
Zombi: Zombie;
begin
Zombi := Zombie.Create(5,10,15);
try
Zombi.ShowLife;
finally
Zombi.Free;
end;
end;

How to save breakpoints using the Delphi IDE?

How can I save breakpoints using the Delphi IDE? I only know how to store the settings in a .dsk file.
I am using Delphi 2007.
I'm assuming from your mention of the .Dsk file that you are aware that the breakpoints are stored in there, but want to save them yourself for some reason. Of course, the easiest method of getting a list of saved breakpoints is simply to read them from the .Dsk file, but that assumes that it has been saved to disk, which usually
occurs when you close the project file.
You can write your own IDE plug-in to get a list of currently-set breakpoints
and save them in any way you want. The minimalist example below shows how to do this - see the GetBreakpoints method for details. To use this in the IDE, you would create a new package which requires
DesignIde.Dcp. Make sure that the output directory for the .Bpl file is either where
your 3rd-party .Bpls are stored on or is on your path. You can then install the
package in the IDE vie Install packages from the IDE's menu.
As you can see, it works by using the BorlandIDEServices interface in the ToolsAPI units to get an IOTADebuggerServices interface, and then uses that to iterate its SourceBkpts list and saves a number of properties of each IOTASourceBreakpoint in that list.
Note that
You can also retrieve a list of address breakpoints and save those in a similar fashion.
Both kinds of breakpoint interface in ToolsAPI have property setters as well as getters, so you could modify existing breakpoints in code and conceivably create new ones.
Code
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ToolsApi;
type
TBreakpointSaveForm = class(TForm)
Memo1: TMemo;
btnGetBreakpoints: TButton;
procedure btnGetBreakpointsClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
protected
public
procedure GetBreakpoints;
end;
var
BreakpointSaveForm: TBreakpointSaveForm;
procedure Register;
implementation
{$R *.DFM}
procedure TBreakpointSaveForm.GetBreakpoints;
var
DebugSvcs: IOTADebuggerServices;
procedure SaveBreakpoint(BreakPoint : IOTASourceBreakpoint);
begin
Memo1.Lines.Add('File: ' + Breakpoint.FileName);
Memo1.Lines.Add('LineNo: ' + IntToStr(Breakpoint.LineNumber));
Memo1.Lines.Add('Passcount: ' + IntToStr(Breakpoint.Passcount));
Memo1.Lines.Add('');
end;
procedure SaveBreakpoints;
var
i : Integer;
BreakPoint : IOTASourceBreakpoint;
begin
Memo1.Lines.Add('Source breakpoint count : '+ IntToStr(DebugSvcs.GetSourceBkptCount));
for i := 0 to DebugSvcs.GetSourceBkptCount - 1 do begin
Breakpoint := DebugSvcs.SourceBkpts[i];
SaveBreakpoint(Breakpoint);
end;
end;
begin
if not Supports(BorlandIDEServices, IOTADebuggerServices, DebugSvcs) then begin
ShowMessage('Failed to get IOTADebuggerServices interface');
exit;
end;
Memo1.Lines.Clear;
SaveBreakpoints;
end;
procedure Register;
begin
end;
initialization
BreakpointSaveForm := TBreakpointSaveForm.Create(Application);
BreakpointSaveForm.Show;
finalization
if Assigned(BreakpointSaveForm) then
BreakpointSaveForm.Free;
end.
procedure TBreakpointSaveForm.btnGetBreakpointsClick(Sender: TObject);
begin
GetBreakpoints;
end;

How to share functions in Delphi?

For example, I have a couple of functions written for my form. Now, I need the exact same functions in another form. So, how can I share them between the two forms? Please, provide a simple example if possible.
Don't put them in your form. Separate them and put them in a common unit, and add that unit to the uses clause where you need access to them.
Here's a quick example, but you can see many of the Delphi RTL units (for instance, SysUtils) that do this. (You should learn to use the VCL/RTL source and the demo apps that are included in Delphi; they could answer many of the questions you've posted more quickly than waiting for an answer here.)
SharedFunctions.pas:
unit
SharedFunctions;
interface
uses
SysUtils; // Add other units as needed
function DoSomething: string;
implementation
function DoSomething: string;
begin
Result := 'Something done';
end;
end.
UnitA.pas
unit
YourMainForm;
uses
SysUtils;
interface
type
TMainForm = class(TForm)
procedure FormShow(Sender: TObject);
// other stuff
end;
implementation
uses
SharedFunctions;
procedure TMainForm.FormShow(Sender: TObject);
begin
ShowMessage(DoSomething());
end;
end.
In more recent versions of Delphi than Delphi 7, you can create the functions/methods in a record instead:
unit
SharedFunctions;
interface
uses
SysUtils;
type
TSharedFunctions = record
public
class function DoSomething: string;
end;
implementation
function TSharedFunctions.DoSomething: string;
begin
Result := 'Something done';
end;
end;
UnitB.pas
unit
YourMainForm;
uses
SysUtils;
interface
type
TMainForm = class(TForm)
procedure FormShow(Sender: TObject);
// other stuff
end;
implementation
uses
SharedFunctions;
procedure TMainForm.FormShow(Sender: TObject);
begin
ShowMessage(TSharedFunctions.DoSomething());
end;
end.
If you need forms. You could use inherited forms. Creating a form that inherit the functions of a parent form.
The most interesting. Any changes in the parent form is reflected a change in inherited forms. You even can inherit form controls (tbutton, tlabel, etc...).
In GUI Delphi7. Option "new form", option "inherited from a existing form".
Example:
//MainForm.pas
type
TMainForm = class(TForm)
procedure MiFunction();
.
.
end;
//ChilForm.pas
type
TChildForm = class(TMainForm)
.
.
end;

How can I access a delphi control from outside the form's unit?

I'm trying to call the Enabled property of a Timer from a procedure defined like this: procedure Slide(Form: TForm; Show: Boolean); and not with a fixed form name (like: Form2.Timer...)
After putting the form's unit in the uses list, this works: Form2.Timer1.Enabled := True;
but the following is not working: Form.Timer1.Enabled := True; (where Form is the form passed as parameter to the procedure.
How to get access to the Timer component on my form?
Thanks in advance.
If every form you're going to pass into your function will have a published field named "Timer1," then you can use the FindComponent method to get a reference to it:
procedure Slide(Form: TForm; Show: Boolean);
var
TimerObj: TComponent;
Timer: TTimer;
begin
TimerObj := Form.FindComponent('Timer1');
Assert(Assigned(TimerObj), 'Form has no Timer1');
Assert(TimerObj is TTimer, 'Form.Timer1 is not a TTimer');
Timer := TTimer(TimerObj);
// Continue using Form and Timer
end;
That's a rather weak interface to program against, though. If you've accidentally neglected to place a timer on your form, or if you've given it the wrong name, or if you've given it a different visibility, you won't discover your mistake until run time (when the assertions fail). And even if the form does meet the required interface, there's no guarantee that it was intentional. There may be lots of forms that have published TTimer fields named Timer1, but they're not all meant to be used with this Slide function. They might already be using their timers for other purposes, so calling Slide on them will break other parts of your program, possibly in difficult-to-debug ways.
It would be a slightly stronger interface if you gave the timer a more descriptive name, such as SlideTimer. Timer1 merely says it was the first TTimer you created on that form, and once you leave the Form Designer, that ceases to be a meaningful designation. You are not required to use the IDE's naming choices.
Another, better, option is to make all your slidable forms have a common base class, and put the timer in that base class. Then, change the parameter type in Slide to take that form class instead of just TForm.
type
TSlidableForm = class(TForm)
Timer1: TTimer;
end;
procedure Slide(Form: TSlidableForm; Show: Boolean);
You seemed concerned that you would have to include a reference to Form2's unit in your Slide unit, and that's generally a good concern to have. You don't want your code to be too tightly coupled since this Slide function should be able to work with more than just one form in one project. But if it's too loose, then you run into the problems I described above. This TSlidableForm class is a compromise; your Slide function isn't bound directly to TForm2 or its unit. Change TForm2 to descend from TSlidableForm.
The_Fox's second suggestion is a variation on my first, but there's still another variation. Instead of passing the name of the timer component, you can pass a reference to the component itself:
procedure Slide(Form: TForm; Timer: TTimer; Show: Boolean);
Now you don't need to use FindComponent to search for the timer to use; you've provided a direct reference to it. The component's name doesn't even matter, so different forms can use different names. You can call it like this:
Slide(Form2, Form2.Timer1, True);
Slide(AnotherForm, AnotherForm.SlideTimer, False);
Once you've come this far, you may go beyond your original question and realize that the timer doesn't even need to belong to the form anymore. You could create it specially for the call to Slide, or the timer could belong to something else entirely (like a data module). But if you're going to create the timer just for the Slide call, then you could use David's suggestion of creating the timer within the routine itself and not have the caller or the form deal with it at all:
procedure Slide(Form: TForm; Show: Boolean);
var
Timer: TTimer;
begin
Timer := TTimer.Create(nil);
try
Timer.OnTimer := ...;
Timer.Interval := 500;
Timer.Enabled := True;
// Put your normal Slide stuff here
finally
Timer.Free;
end;
end;
You cannot access the Timer from your procedure because your parameter is a TForm, and TForm does not have a Timer1 member. You have to adjust your procedure like this:
uses
Unit2; //unit with your form
procedure Slide(Form: TForm2; Show: Boolean); //change TForm2 to the classname you use
begin
Form.Timer1.Enabled := True;
end;
Edit:
If you want to pass any form, you can try this:
procedure Slide(Form: TForm; const aTimerName: string; Show: Boolean);
var
lComponent: TComponent;
begin
lComponent := Form.FindComponent(aTimerName);
if Assigned(lComponent) and (lComponent is TTimer) then
TTimer(lComponent).Enabled := True;
end;
Call like this from a button on your form:
procedure TForm2.Button1Click(Sender: TObject);
begin
Slide(Self, 'Timer1', False);
end;
Or you let your Form inherit an interface with methods to turn on the timer. It's a little bit more complicated though.
Add the unit to the uses list.
...
implementation
uses Unit2;
{$R *.dfm}
...
Use Form2's unit name in uses list of current unit.
For your Edit:
By using TForm you cant access TTimer because TForm has no fields or properties as TTimer.
So you need to use TForm1 as the parameter.
If you are having a form say Form1, for which you are creating multiple instances and showing to the user, then change your procedure syntax to procedure Slide(Form: TForm1; Show: Boolean);
But if you are having multiple forms with different components, it will become difficult. You need to overload procedures with different parameters. Below code shows the approach.
Form1 Unit
var
Form1: TForm1;
implementation
{$R *.dfm}
uses Unit3;
procedure TForm1.Button1Click(Sender: TObject);
begin
Slide(Form1, True)
end;
Form2 Unit
var
Form2: TForm2;
implementation
{$R *.dfm}
uses Unit3;
procedure TForm2.Button1Click(Sender: TObject);
begin
Slide(Form2, True)
end;
Unit in which your procedures lies
unit Unit3;
interface
uses Forms, ExtCtrls, Unit1, Unit2;
procedure Slide(Form: TForm1; Show: Boolean) overload;
procedure Slide(Form: TForm2; Show: Boolean) overload;
implementation
procedure Slide(Form: TForm2; Show: Boolean);
begin
Form.Timer1.Enabled := True;
end;
procedure Slide(Form: TForm1; Show: Boolean);
begin
Form.Timer1.Enabled := True;
end;
end.
Just to add some more information.
In a Delphi project, code is organised into units. Each unit is a file with a name and a .pas extention.
The unit has the following form:
unit Name;
interface
uses
// The definition of these units can be used both in the
// interface as in the implementation section.
unit1, unit2;
// Public interface, visible to other units that use this unit.
implementation
uses
// The definition of these units can be used only in the
// implementation section.
unit3, unit4;
// Private implementation, not visible outside.
initialization
// code to initialize the unit, run only once
finalization
// code to cleanup the unit, run only once
end.
A unit can use anything defined in the unit as long as it is defined before it is beïng used.
Sometimes this leads to confusing situations if names are identical:
unit1;
interface
type
TTest = Integer;
// ...
unit2;
interface
type
TTest = Boolean;
// ...
unit3;
interface
uses
unit1, unit2;
var
a: TTest; // Which TTest?
// ...
You can solve this by either knowing the evaluation order, or use a unit prefix:
unit3;
interface
uses
unit1, unit2;
var
a: unit1.TTest; // TTest from unit1
b: unit2.TTest; // TTest from unit2
// ...
In your case, you need to use the unit in which Form2 is defined.
If the timer is needed by both forms, you can also use a datamodule (just like a form, you can drag nonvisible components to it but they won't be visible). Both forms then can use the datamodule.
Edit
You try to use:
procedure Slide(Form: TForm; Show: Boolean);
And TForm has no Timer1.
You can do the following:
procedure Slide(Form: TForm2; Show: Boolean);
If TForm2 is the form containing the Timer.
The easiest way is to find it on the form:
procedure Slide(Form: TForm; Show: Boolean);
var
Timer: TTimer;
begin
Timer := Form.FindComponent('Timer1');
if Assigned(Timer) then
Timer.Enabled := True;
end;
To appease David ;-), here's a more "type-safe" alternative:
procedure Slide(Form: TForm; Show: Boolean);
var
i: Integer;
begin
// Could use a TComponent and for..in instead. This works in
// all Delphi versions, though.
for i := 0 to Form.ComponentCount - 1 do
if Form.Components[i] is TTimer then
TTimer(Form.Components[i]).Enabled := True;
end;♦♠
A simple (and OOP) way to implement this is to use interfaces.
Declare an interface ISlideable which defines a SlideTimer property (with getter and setter methods) and then write the Slide method like
Slide(const Target: ISlideable; Show: Boolean);
And every form which should be passed says that it is Slideable
MyFormN = class(TForm, ISlideable)
...

How to pass data between forms in Delphi?

It may seem a little newbie, but I really have got problem with it. I have a form (not the main one)for getting many different data from the user and I want to pass it to a manager class for creating an object with these. The problem is that I can't have this class to use the other unit (getting circle uses) and also it doesn't have access to the manager class instance (which is in main form).
So, what shall I do? I've already considered using public variable but I have a bad feeling about it (regarding OOD patterns).
My suggestion is to decouple data from the GUI because this is causing your problem.
If you have a form which gathers data from the user then you should distinguish the data from the form(TForm).
For example, let's assume that you have some instance of TForm and a form, which is built from three fields: username, age and location. You want the user to enter those three things, but when the user closes the form, you should pass this inserted data onto some object. Form closes, it is freed, but the object persist. Then you pass this object to your manager object.
Simple example:
This is your record which will hold the data
type
TGatheredData = record
Name: String[40];
Age: Byte;
Location: String[40];
end;
Your TForm1 might have an aditional constructor:
constructor TForm1.Create(AOwner: TComponent; var GatheredData: TGatheredData );
begin
inherited Create(AOwner);
FGatheredData := GatheredData;
//you may want to deserialize GatheredData here and show the data in your form controls
end;
You call it, pass GatheredData and then your are showing your form.
Next, when closing form, you pick upd the data from the form controls.
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if Self.ModalResult = mrOk then
begin
//serialize your object
FGatheredData.Name := '';//name taken from control f.e. TEdit
FGatheredData.Age := '';//name taken from control f.e. TSpinButton
FGatheredData.Location := '';//name taken from control f.e. TEdit
end;
end;
Having this record of data, you may now pass it in the same manner to your Manager object.
You decoupled data from GUI in this way, and you may easly plugin in your record to a number of different forms.
Just remember to declare your record type in external unit and use that unit in your manager unit and forms unit.
Hope this helps a little.
The "manager class" shouldn't be in either form's unit, but in its own. By separating GUI code from bussiness logic you avoid problems such like this.
[Edit: I originally put this answer in a comment, but decided to move it out into full answer. TDatamodules are too important and too common in Delphi not to emphasize them and they provide built-in easy-to-use means of seperating gui from logic and data.]
Other people have given good comments about decoupling gui from the logic and data. Surprisingly, I don't think anybody has mentioned that in Delphi TDatamodules are one main means of doing this. You put your data and logic on the Datamodule, then have both forms "use" the Datamodule to get access to its data and methods. Here is brief intro: http://delphi.about.com/od/database/l/aa101601a.htm
Both of your forms (and other forms) can access datasets or other data/datastructures that are located on/in a Datamodule unit. There should be an easy to find sample project out there illustrating the setup, since it is (or at least was) the standard way to construct Delphi apps.
If I understand your question properly then you want the manager to manage the forms (not the forms to access the manger). Right? You can't close the Main Form as if you do you close the application but you CAN Hide it. (unless you create a console app). But it poses a nice little problem :)
So... Splash form (Main Form) is:
.
.
.
uses
ManagerU;
type
TFormSplash = class(TForm)
procedure FormPaint(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
Manager: TManager;
end;
var
FormSplash: TFormSplash;
implementation
{$R *.dfm}
procedure TFormSplash.FormCreate(Sender: TObject);
begin
Manager := TManager.Create;
end;
procedure TFormSplash.FormDestroy(Sender: TObject);
begin
Manager.Free;
end;
procedure TFormSplash.FormPaint(Sender: TObject);
begin
if Visible then
begin
Manager.GetData(Self);
Hide;
Manager.DoDataStuff;
Close;
end;
end;
end.
DaaObject is:
unit DataObjectU;
interface
uses classes;
type TDataObject = class(TObject)
Data: string;
end;
implementation
end.
Manager is:
interface
uses DataObjectU;
type
TManager = Class(Tobject)
MyData: TDataObject;
constructor Create; virtual;
destructor Destroy; override;
procedure GetData(OwnerForm: TForm);
procedure DoDataStuff;
end;
implementation
uses DataFormU;
{ TManager }
constructor TManager.Create;
begin
inherited Create;
MyData := TDataObject.Create;
end;
destructor TManager.Destroy;
begin
MyData.Free;
inherited;
end;
procedure TManager.DoDataStuff;
begin
// do stuff with data here
end;
procedure TManager.GetData(OwnerForm: TForm);
var
MyDataForm: TDataForm;
begin
MyDataForm := TDataForm.Create(OwnerForm);
try
if MyDataForm.ShowModal = mrOK then
begin
MyData.Data := MyDataForm.Data;
end;
finally
MyDataForm.Free;
end;
end;
end.
The Dataform is:
type
TDataForm = class(TForm)
btnOK: TButton;
procedure btnOKClick(Sender: TObject);
private
function GetData: String;
{ Private declarations }
public
{ Public declarations }
MyData: TDataObject;
property Data: String read GetData;
end;
var
DataForm: TDataForm;
implementation
{$R *.dfm}
procedure TDataForm.btnOKClick(Sender: TObject);
begin
MyData := TDataObject.Create;
ModalResult := mrOk;
end;
function TDataForm.GetData: String;
begin
Result := MyData.Data;
end;
You will need to fill in the rest of the unit code and free some stuff but essentially this:
Start Program (Creates Splash)
Splash Creates the manager calls it to get data from the dataform then hides itself
calls manager to manage the data
when manager is done it then closes.
There is no other way to shut it down now except through task manager!)
Tim
To solve circular refrence error, you use that unit in implementation section.
implementation
{$R *.DFM}
Uses <Your Unit>;
end.
Having this 3 units:
FormMain
FormEdit
UnitMyClass
You create your object in FormMain and pass it to the FormEdit in a function like:
class function FormEdit.EditMyObject(AObject: TMyClass): boolean;
this function will showModal the form. The form will do the changes to the object, and finally return True if user pressed OK.
As you can see in UnitMyClass there is no reference to FormMain or FormEdit
FWIW, I did a whole presentation on this topic in a CodeRage 9 video. It can be seen here:
https://youtu.be/qqKx8fQTTfI

Resources