I'm building an installer using Inno Setup and the programming is done via Delphi/Pascal for the custom dialog screens. It's almost done, I'm just wondering how I can disable some text boxes or other components dependent on other actions like the click of a radio button.

Specific example: I have 2 radio buttons, one for locating a key file on the local machine, another for inputting it manually. If you click the radio button to find it on the local machine, it activates a button where you can browse and find it locally. If you click the second radio button, the browse button stays grayed out and disabled.

Recommended Answers

All 37 Replies

Something.Enabled:=false;

Holy hell, I was trying RadioButton.Disabled := True; and wondering why it wasn't working.......what a drag. Thanks.

Lastly, do you know how to make this happen in relation to other components?

Checkbox.OnClick := something.something;
TEdit.Enabled := false;

How do I make the TEdit disabled when the CheckBox is checked?

I havent played with inno setup much, but you can test the check box value in an onclick event and set

edit1.enabled:=not checkbox1.checked;

so if its checked it will be disabled, if its not checked enabled..

The correct way for this would be to make your dialog showed modally which would implicitly prevent other forms to be modified. And it would also prevent them to hide your form behind themselves. And also there is that cool pinging sound... :)
There was a lot of time I tought something had freezed, and found a hidden dialog behind its form.

the state of a form wouldnt help with turning a text box to usable or not.

I havent played with inno setup much, but you can test the check box value in an onclick event and set

edit1.enabled:=not checkbox1.checked;

so if its checked it will be disabled, if its not checked enabled..

The problem with this is that I can't reference checkbox in a function.....or I can't seem to. Here's the basics of what I have...

procedure CheckBoxOnClick(Sender: TObject) ;
begin
end;


procedure CreateTheWizardPages;
var
  Page: TWizardPage;
  DataDirectoryPage: TInputDirWizardPage;
  RadioButton1, RadioButton2, RadioButton3: TRadioButton;
  StaticText1, StaticText2, StaticText3, StaticText4: TNewStaticText;
  CheckListBox: TNewCheckListBox;
  CheckBox: TNewCheckBox;
  BitmapImage: TBitmapImage;
  BitmapFileName: String;
  StaticText: TNewStaticText;
  Edit, Edit2: TEdit;
  Labell, Labell2: TLabel;
  Panel1: TPanel;

begin

Page := CreateCustomPage(wpSelectDir, '', '');

 Page := CreateCustomPage(Page.ID, 'ODBC Setup', 'Legacy Applications Require ODBC Connectivity')

  BitmapFileName := ExpandConstant('{tmp}\db.bmp');
  ExtractTemporaryFile(ExtractFileName(BitmapFileName));
  BitmapImage := TBitmapImage.Create(Page);
  BitmapImage.Top := 10;
  BitmapImage.Left := Page.SurfaceWidth - 60;
  BitmapImage.AutoSize := True;
  BitmapImage.Bitmap.LoadFromFile(BitmapFileName);
  BitmapImage.Parent := Page.Surface;

  StaticText1 := TNewStaticText.Create(Page);
  StaticText1.Top := 10;
  StaticText1.Left := ScaleX(8);
  StaticText1.Caption := 'Enter Your ODBC Information. You may require the assistance of your' + #13#10 + 'Database Administrator.';
  StaticText1.AutoSize := True;
  StaticText1.Parent := Page.Surface;

  CheckBox := TNewCheckBox.Create(Page);
  CheckBox.Top := 100;
  CheckBox.Width := Page.SurfaceWidth;
  CheckBox.Height := ScaleY(17);
  CheckBox.Caption := 'Skip ODBC Configuration';
  CheckBox.Checked := false;
  CheckBox.Parent := Page.Surface;
  CheckBox.OnClick := @CheckBoxOnClick;

In the procedure at the top, if I put checkbox.anything in there, it doesn't know what checkbox is. Or if I use Sender.enabled then it doesn't know what ENABLED means because it's not a function of TObject. So if I change it to (Sender: TCheckBox) then it says there is a type mismatch.....what do I do? Please, been on this problem for 3 days and Inno help is pretty non existent.

In the procedure at the top, if I put checkbox.anything in there, it doesn't know what checkbox is. Or if I use Sender.enabled then it doesn't know what ENABLED means because it's not a function of TObject. So if I change it to (Sender: TCheckBox) then it says there is a type mismatch.....what do I do? Please, been on this problem for 3 days and Inno help is pretty non existent.

Thanks for the easy question.
First, the problem is that you've changed your method signature. In Delphi, it would require the caller to explicitly cast the sender parameter to TCheckBox to be able to use it. This won't be the case. Instead you must receive a TObject, and later typecast it yourself to TCheckBox: Ex 5.1 step 4 Testing the Sender parameter

In case there would be some crap with the runtime type information, just use the forced one: Ex 5.1 step 6 An alternative typecasting operator (Of course if somehow it's not a TCheckBox, this won't work either.)

Wow, thanks. Really close but I don't have it yet.
So in Step4 that you posted, there's a download on the final page for homework answers and there's an example on that PDF which contains a method:

procedure TfrmMasterControl.chkLight1Click(Sender: TObject);
begin
frmTrafficLight1.Auto := chkLight1.Checked;
btnStepLight1.Enabled := not chkLight1.Checked;
end; // end procedure TfrmMasterControl.chkLight1Click

That's what I need except when I try to reference checkbox like they're referencing chkLight1, it doesn't know what checkbox is. And I've tried using checkbox1 thinking the name was a constant.

Here's the full code example they gave, the difference with my code is I don't have these interface, uses and type declarations in my code.

unit MasterControlU;
{ Developed from the single traffic light display.
This version introduces a master controller for three lights.
Uses the previous display as a VFI template (TemplateU).
Derives three (empty) displays from TemplateU.
The Master Controller switches individual displays between
automatic and manual operation and changes cycle lengths.
Each individual controller has its own cycle unit length,
set in tenths of a second:
Yellow = 1 cycle unit
Green = 3 cycle units
Red = 4 cycle units
}
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms, Dialogs, StdCtrls, Spin;
type
TfrmMasterControl = class(TForm)
chkLight1: TCheckBox;
btnStepLight1: TButton;
sedCycle1: TSpinEdit;
{ Same for the 2nd and 3rd controls }
procedure FormShow(Sender: TObject);
procedure chkLight1Click(Sender: TObject);
procedure btnStepLight1Click(Sender: TObject);
procedure sedCycle1Change(Sender: TObject);
{ same for the 2nd and 3rd controls }
end;
var
frmMasterControl: TfrmMasterControl;

implementation
uses Controller1U, Controller2U, Controller3U;
{$R *.dfm}
procedure TfrmMasterControl.FormShow(Sender: TObject);
begin
frmTrafficLight1.Show;
frmTrafficLight2.Show;
frmTrafficLight3.Show;
end; // end procedure TfrmMasterControl.FormShow
procedure TfrmMasterControl.chkLight1Click(Sender: TObject);
begin
frmTrafficLight1.Auto := chkLight1.Checked;
btnStepLight1.Enabled := not chkLight1.Checked;
end; // end procedure TfrmMasterControl.chkLight1Click
procedure TfrmMasterControl.btnStepLight1Click(Sender: TObject);
begin
frmTrafficLight1.StepToNext;
end; // end procedure TfrmMasterControl.btnStepLight1Click
procedure TfrmMasterControl.sedCycle1Change(Sender: TObject);
begin
frmTrafficLight1.CycleLength := sedCycle1.Value;
end; // end procedure TfrmMasterControl.sedCycle1Change
{ Same for the 2nd and 3rd controls }
end. // end unit MasterControlU
unit TemplateU;
{ The VFI template for the actual traffic light displays.
All the code is specified here.
}
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms, Dialogs, ExtCtrls, StdCtrls,
TrafficLightU;
type
TfrmTrafficLight = class(TForm)
{Standard RAD declarations}
private
MyTrafficLight: TTrafficLight;
FPeriod: integer;
FState: string;
FStopLight: TColor;

FGoLight: TColor;
FCautionLight: TColor;
FAuto: boolean;
FCycleLength: integer;
procedure UpDateDisplay;
procedure SetAuto(const Value: boolean);
public
property Period: integer read FPeriod write FPeriod;
property State: string read FState write FState;
property StopLight: TColor read FStopLight write FStopLight;
property CautionLight: TColor read FCautionLight
write FCautionLight;
property GoLight: TColor read FGoLight write FGoLight;
property Auto: boolean read FAuto write SetAuto;
property CycleLength: integer read FCycleLength
write FCycleLength;
procedure StepToNext;
end;
var
frmTrafficLight: TfrmTrafficLight;
implementation
{$R *.dfm}
procedure TfrmTrafficLight.tmrTrafficLightTimer(Sender: TObject);
begin
StepToNext;
end; // end procedure TfrmTrafficLight.tmrTrafficLightTimer
procedure TfrmTrafficLight.FormShow(Sender: TObject);
begin
CycleLength := 10; // default value
MyTrafficLight := TTrafficLight.Create;
State := 'Caution';
StepToNext; // goes to red
Auto := False; // start in manual
end; // end procedure TfrmTrafficLight.FormShow
procedure TfrmTrafficLight.StepToNext;
begin
MyTrafficLight.NextState(Self);
UpDateDisplay;
end; // end procedure TfrmTrafficLight.StepToNext
procedure TfrmTrafficLight.UpDateDisplay;
begin
tmrTrafficLight.Interval := Period;
lblTrafficLight.Caption := State;
shpRed.Brush.Color := StopLight;
shpYellow.Brush.Color := CautionLight;

shpGreen.Brush.Color := GoLight;
end; // end procedure TfrmTrafficLight.UpDateDisplay
procedure TfrmTrafficLight.SetAutoconst Value: boolean);
begin
tmrTrafficLight.Enabled := Value;
FAuto := Value; // not really needed, never read
end; // end procedure TfrmTrafficLight.SetAuto
end. // end unit LightControlU
unit Controller1U;
{ All three displays similar to this.
To support substitution (TrafficLightU), all code and data in
parent.
Also, no need for any extension or specialisation here.
}
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms, Dialogs, ExtCtrls, StdCtrls, TemplateU;
type
TfrmTrafficLight1 = class(TfrmTrafficLight);
var
frmTrafficLight1: TfrmTrafficLight1;
implementation
{$R *.dfm}
end.
unit TrafficLightU;
{ Model of the application / domain object }
interface
uses Forms;
type
TTrafficLight = class (TObject)
public
procedure NextState (AClient: TForm);
end;
implementation

uses TemplateU,
Graphics; // for TColor
{ TTrafficLight }
procedure TTrafficLight.NextState (AClient: TForm);
begin
if (AClient is TfrmTrafficLight) then // similar to use of Sender
with TfrmTrafficLight(AClient) do // - typecasting and 'with'
if State = 'Stop' then // all references to client form
begin
Period := 300 * CycleLength; // update values on client form
State := 'Go';
StopLight := clBlack;
GoLight := clGreen;
end
else if State = 'Go' then
begin
Period := 100 * CycleLength;
State := 'Caution';
GoLight := clBlack;
CautionLight := clYellow;
end
else
begin
Period := 400 * CycleLength;
State := 'Stop';
CautionLight := clBlack;
StopLight := clRed;
end;
end; // end procedure TTrafficLight.NextState
end. // end unit TrafficLightU

checkbox1 would be the default name for the first checkbox dumped on your form.. so if they gave you the answers Im confused why you need to ask..

That's what I need except when I try to reference checkbox like they're referencing chkLight1, it doesn't know what checkbox is. And I've tried using checkbox1 thinking the name was a constant.

The main thing I hate in delphi is global variables...
So 1st, the name is TComponent.Name. It's a field. You can find components by name calling the appropriate methods, and it helps serialization.
2nd there are global variables, they can be accessed from everywhere, like Form1 always holds the pointer to the single instance created by Delphi from your TForm1. It have nothing to do with the name. It's a global variable. Of course the default names and values are the same, but just coincidence, they are not the same thing. Using global variables is deprecated, but Delphi is old.
3rd, this is what you need: the sender! In correct OO programing, instead of global variables, pointers are passed around. Well, it's much better than global variables, because... so this is the only thing you need in a correct design. And this is the sender. You just have to forget the two before. So now, instead of chkLight1.Checked; you write (Sender as TCheckBox).Checked;
Alternatively with globals, you could write Form1.chkLight1.Checked; ... if you would have those globals, but this was the 1st problem I guess.

You can read the whole article I've linked from, it'll help you clear this.

The main thing I hate in delphi is global variables...
So 1st, the name is TComponent.Name. It's a field. You can find components by name calling the appropriate methods, and it helps serialization.
2nd there are global variables, they can be accessed from everywhere, like Form1 always holds the pointer to the single instance created by Delphi from your TForm1. It have nothing to do with the name. It's a global variable. Of course the default names and values are the same, but just coincidence, they are not the same thing. Using global variables is deprecated, but Delphi is old.
3rd, this is what you need: the sender! In correct OO programing, instead of global variables, pointers are passed around. Well, it's much better than global variables, because... so this is the only thing you need in a correct design. And this is the sender. You just have to forget the two before. So now, instead of chkLight1.Checked; you write (Sender as TCheckBox).Checked;
Alternatively with globals, you could write Form1.chkLight1.Checked; ... if you would have those globals, but this was the 1st problem I guess.

You can read the whole article I've linked from, it'll help you clear this.

I read the whole article (awesome, thanks). And now I understand about the typecasting, but it still won't work for me. This is what I have:

procedure CheckBoxOnClick(Sender: TObject) ;
begin
if Sender is TCheckBox then
(Sender as TCheckBox).enabled := false;
end;

And when I run it, it says Identifier expected and points to the enabled line. Am I using it right? If I replace the enabled line with a line to show a message box, it works fine.

Yes

TCheckbox is a TYPE, Checkbox1 or whatever is an instance of that type..

You shouldnt need to check that the send is of type checkbox, if you only assign the procedure to a checkbox, then its gonna be one.. and its not the sender you are worried for really - however.. If you want more explaination.. theres a tutorial at http://www.xcalibur.co.uk/training/Delphi2005 (dont be surprised at the 2005, its been updated since then) and you'll find it covers exactly this kind of thing.

I read the whole article (awesome, thanks). And now I understand about the typecasting, but it still won't work for me. This is what I have:

procedure CheckBoxOnClick(Sender: TObject) ;
begin
if Sender is TCheckBox then
(Sender as TCheckBox).enabled := false;
end;

And when I run it, it says Identifier expected and points to the enabled line. Am I using it right? If I replace the enabled line with a line to show a message box, it works fine.

It's fine, moreover this cod works for me with copypaste, I've tested:

procedure TForm1.qweClick(Sender: TObject);
begin
if Sender is TCheckBox then
(Sender as TCheckBox).enabled := false;
end;

However, I have Delphi 2k5, and just to be on the safe side, try something like this:

procedure TForm1.qweClick(Sender: TObject);
var meowmeow: TCheckBox;
begin
if (Sender is TCheckBox) then
meowmeow:= TCheckBox(Sender);
meowmeow.Enabled:=false;
end;

Hopefully this will expose the problem...
Here I've declared a local variable, and cut your statement in half with it, so if the error occurs again, you'll know exactly, if it's the typecast or the property set.
Also the is check with the as casting is not necessary, since as casting do an is check. But here I've cut it in half into an is check and a forced casting, also for debugging.
And also, just to be safe, try writing every possible brackets. This technic is called "debugging crap". :D
*Edit: Almost forgot, watch out for line numbers in the error messages: Delphi's IDE likes to underline text in another line. You must check this too.

Sadly I must admit, that the error occurs only on your system, and this is not odd, cause Delphi is old, and sometimes writing the same code slightly differently in another version does this. Try 2k5 or newer versions, those are more stable, and this won't occur so often.
However at least I can congratulate you for writing probably your first real OO code.
Good luck, and if you've got another error, post it, maybe then I'll find out.

Delphi isnt old, however, inno setup is more the key here, rather than delphi itself, as thats where the code was being used.

I'm trying to take everyone's post into consideration because I'm glad you're helping me.

First off, the link......it didn't seem to work for me. I clicked it and it said the page cannot be displayed.

The other post that split up the code, it worked! Kind of. When I click the checkbox now it disables it fine. But I want to click the checkbox and disabled a separate form component.....more specifically an edit box and label.....2 of each. I'm guessing I pass them in as parameters but when I try that it I have a problem again.
I call the method as follows:

CheckBox.OnClick := @qweClick;

That doesn't seem right so I change it to something that looks more familiar to me as a Java developer so it looks like:

CheckBox.OnClick := qweClick(checkBox);

Then it tells me there's a type mismatch. Still trying to figure it out......

Hmm, I'll have to mail the person ask why its not working..

PS http://www.xcalibur.co.uk/training/Delphi2005 is working now!

On click needs a procedure assigned to it so if you have

procedure mything.something_click(Sender : TObject)
begin
.. do something
end;

button1.Onclick = something_click;

I looked at the tutorial and a pile of other pages on the web and still haven't gotten it completely.

I have:

procedure qweClick(Sender: TObject);
   var
    check1: TEdit;
   begin
    if (Sender is TEdit) then
     check1 := TEdit(Sender);
     check1.enabled := false;
   end;

which works great but doesn't do exactly what I need. I can call the function using

CheckBox.OnClick := @qweClick;

which will only pass itself as a parameter or I can call it using

qweClick(Edit);

which will pass in a form component of my choice but then it's not related to an OnClick function.

My problem is I need to call it like

CheckBox.OnClick := qweClick(Edit);

but that gives me an error. How can I call this procedure with another form component as a parameter? I want to be able to click the checkbox to disable the edit box.

I would say call Edit.Click but edit boxes dont have such a function

If you know the control you want, make a routine you pass the edit box too, and call the routine with that from your onclick method.

The other post that split up the code, it worked! Kind of. When I click the checkbox now it disables it fine. But I want to click the checkbox and disabled a separate form component.....

The easyest way would be: ((Sender as TCheckBox).Parent as TCustomForm).SomeOtherComponent.Enabled:=False Problem is, you don't have the form's (called TCustomForm) source, if it has a source at all.

So you'll just have to use FindComponent: ((Sender as TCheckBox).Parent.FindComponent('SomeOtherComponent') as TEdit).Enabled:=False (A common mistake would be to use FindComponent alone, which would be translated as Self.FindComponent, and then it would search only the form that has the event as it's method, and not the one that have fired that method. Then if those forms are different, the program will just fail without any error. Still, every example I've found by google do this, so I won't post any tutorial link now, and watch out don't strip the begining!)

*Edit: Parent is a property holding the form that draws the component. Also you could use a superclass of TCheckBox or TEdit to make it more general, but now I won't search for those classnames. Also this code works for me as it is, but you may have to combine it with your working code, since you had problems before.

Sorry for the late answer. I didn't expect the second code to work, because that does exactly the same thing that the 1st one. :D Delphi is old indeed. :P (It's not a fact derived from its release date. It's just how I feel.) I'll try to check back soon.

Tipp: When you post code, use for highlighting.[CODE=Delphi] for highlighting.

This is going to sound stupid but why cant you just put the names of the components in the original click method and enable/disable them?

Thanks, I'll do some Google searches on FindComponent and see if I can get something going there. I have no idea what you posted but I think it'll make more sense once I look around.

This is going to sound stupid but why cant you just put the names of the components in the original click method and enable/disable them?

You mean call this?
CheckBox.OnClick := DisableEditBox(EditBox);
And then disable the EditBox in the method? I've tried every possible combination, it always says there's a type mismatch when compiling the code. Or did I misunderstand you?

You mean call this?
CheckBox.OnClick := DisableEditBox(EditBox);
And then disable the EditBox in the method? I've tried every possible combination, it always says there's a type mismatch when compiling the code. Or did I misunderstand you?

No but the Checkbox_OnClick method could just say

Editbox.Enabled:=false;

You seem to be over complicating what you want to do

No but the Checkbox_OnClick method could just say

Editbox.Enabled:=false;

You seem to be over complicating what you want to do

I tried that and had the following errors:

1. If I put the CheckBox_OnClick procedure above the procedure which creates the forms, I can't reference Editbox because I haven't created it yet. It's created in the CreateTheWizardPages procedure where all my installer dialog pages are created.
2. If I put the CheckBox_OnClick procedure below the procedure which creates the forms, the compiler complains because it runs into the @Checkbox_OnClick procedure call before finding the procedure. I can't call it in the code before it's been declared.

So the only way to use the Editbox is to either pass it into the procedure as a parameter (which I've given up on) or to reference it as a (Sender as TCheckBox).Parent.FindComponent('Editbox') form component. And this is also proving very difficult in Inno. I wish I could find just one example of someone disabling a form component in Inno by clicking on another form component. My life would get much easier at this point.

This is going to sound stupid but why cant you just put the names of the components in the original click method and enable/disable them?

For short, there is no such thing "putting in the name". You must have a reference (memory address) of the object you're going to use. When you say you put in the name of something, it may be a name of a global (like Form1) holding the reference for that object, or a field of the form which has that method (like writing Button1, it's like Self.Button1). The earlier case is just nc (globals=deprecated), and the later is a valuable shortcut set up for you by the IDE. But then if you use a field of an object, you must have a source code of it in the same file or in the uses clause to allow the compiler to calculate the offset of that field related base address.

So when you write Button1.Enabled:=False then the compiler will:
- After not finding a local variable called Button1, it'll look up the class of the method (it's TForm1 and not TForm) if it contain a field called Button1.
- It does, so it calculates the offset of that field (knowing the size of all the fields before it) from the source code, adds it up to the base address of Self, and gets the memory address of that field holding the reference to Button1.
- It then retrives the value from that address, so now it has the base address of Button1.
- Then it looks for an Enabled field, property, or whatever in the source of TButton, again to calc it's offset. Not finding TButton's source locally, it'll look among the uses, and it'll find it in the Forms unit at last.
- Calculates offset again, calls method, writes field, or whatever, it goes on.
Sorry, this description is highly compressed, so it may be inaccurate.

Then this: ((Sender as TCheckBox).Parent.FindComponent('SomeOtherComponent') as TEdit).Enabled:=False So you get the origin of each called events by the Sender parameter, it's a cool thing. But for events to be versatile, it's a TObject, so a TButton and a TEdit can call the same event. But then I know it must be a TCheckBox, and cast it to access things that TObject doesn't have. Now then I know that every visual control which can be painted have a Parent attribute pointing to a TForm that displays them. So now I access that form. Too bad, dynamically created forms don't have fields like a form created by IDE has, and even if a form has those fields, you can't access them without the source (compiler cant look up the offset). But those are still backward compatible with TForm, and you can access regular TForm things. Here this is enough, because there is a whole system set up just to assist these things for us: Every TComponent has a name (which is a field, like its caption, color or whatever), and an Owner, and you can ask the Owner about those components' addresses by their name. But that call returns TComponent, again to be versatile, so knowing your cast won't fail, you just do it again, and you can access specific things yet again. That's it. (I assume another thing: That the form controls have the same parent and owner. It's just because in the 99% of the cases it would cause problems if they would be different.)

Why: Well, it may seem complicated, but it'll be easier in the end: Just think about it, if you have to access a component on a form written by another programmer by "writing it's name", you would have to include his code in your uses clause, and keep it up to date. But if each of you use a system set up by TForm, then you can write your code completely separated, moreover every version of your and his code will be compatible. Just imagine, he ads a field, and he have to send you his code just to let you recompile yours with it. This suck is called dependency.
And because it's not like this, we've successfully disabled a component in innosetup knowing nothing about innosetup at all.

Please don't give me negative rep for writing alot again. I've already learned you don't like it, I've just wanted to answer the question. Sorry again.

1. If I put the CheckBox_OnClick procedure above the procedure which creates the forms, I can't reference Editbox because I haven't created it yet. It's created in the CreateTheWizardPages procedure where all my installer dialog pages are created.

Makes sense. Like you can't change a caption on a button and after then create that button.

2. If I put the CheckBox_OnClick procedure below the procedure which creates the forms, the compiler complains because it runs into the @Checkbox_OnClick procedure call before finding the procedure. I can't call it in the code before it's been declared.

The problem must be something else. It's irrelevant what order you put your methods in your source, because the compiler makes 2 runs compiling a code. Even the oldest assembler can "jump forward". You should quote the error messages completly. But it's also highly probable that the compiler understood something other that you meant.

Last word: Have the original problem been solved by my code, or do you need any more help? It would be nice to make that program before going offtopic.

procedure CheckBoxOnClick(Sender: TObject) ;
var
  a_Checkbox: TNewCheckbox;
begin
  if Sender is TNewCheckBox then
  begin
    a_Checkbox := TNewCheckBox(Sender);
    edit1.enabled := not a_Checkbox.checked;
///do what ever you want here...with a_Checkbox...
  end;
end;

For short, there is no such thing "putting in the name". You must have a reference (memory address) of the object you're going to use. When you say you put in the name of something, it may be a name of a global (like Form1) holding the reference for that object, or a field of the form which has that method (like writing Button1, it's like Self.Button1). The earlier case is just nc (globals=deprecated), and the later is a valuable shortcut set up for you by the IDE. But then if you use a field of an object, you must have a source code of it in the same file or in the uses clause to allow the compiler to calculate the offset of that field related base address.

thank you for your pedantic post, putting the name of the component in is not an unrealistic question - it hadnt been mentioned before it was created on the fly - hence it seemed that the issue was being over complicated.

Ive been coding in delphi for over 20 years, I can assure you I know more than well the name of the component is for my convienience not the computers.. In fact I feel at this point, if you look in the special thanks of delphi 2006, 2007 you'll find my name there, similarly its in the team for 2009.. So, believe me I do know what Im talking about - I just was asking a simple question and didnt need your rather pedantic comment.

I needed to establish more information to give a proper answer and was going to say if theres multiple checkboxes, with associated editboxes, a simple lookup table would make some sense and you could have pairs of checkboxes and editboxes (and any other related component) which would make the coding simple.

thank you for your pedantic post, putting the name of the component in is not an unrealistic question - it hadnt been mentioned before it was created on the fly - hence it seemed that the issue was being over complicated.

Well, in the first post I answered he wanted to use sender or the correct type, but didn't know how to combine them. I assumed he has a reason doing so, and helped doing so, but now that you say... I just hope I was right. Now I'm also interested.

And sorry for answering your question, it was a good and common one, and I usually answer those. If I would had taken it as a stupid one I wouldn't answered at all. Typing so much I hope it will still help somebody. :|

Then this: ((Sender as TCheckBox).Parent.FindComponent('SomeOtherComponent') as TEdit).Enabled:=False So you get the origin of each called events by the Sender parameter, it's a cool thing. But for events to be versatile, it's a TObject, so a TButton and a TEdit can call the same event. But then I know it must be a TCheckBox, and cast it to access things that TObject doesn't have. Now then I know that every visual control which can be painted have a Parent attribute pointing to a TForm that displays them. So now I access that form.

Wow, lots of discussion going here now, that's good. I tried using the FindComponent('Edit1') line of code that you posted there and it compiled just fine but when I ran the program and clicked on the CheckBox, it gave me an error saying it couldn't call proc. I then changed it to FindComponent('jkdfsdhjassdf') which refers to nothing and it still compiled, ran, and gave me the same error. So even though I'm putting in Edit1 which is the name of the EditBox on my dialog, it's not able to find it when I run the procedure by clicking the CheckBox. I even assign Edit1.Name := 'Edit1'; and it still does the same thing.

Please don't give me negative rep for writing alot again. I've already learned you don't like it, I've just wanted to answer the question. Sorry again.

Are you referring to LizR? I didn't give any negative rep, I'm kind of glad you're taking the time to type it out and explain it.....both of you. And when I search Google for my issue, I keep getting this thread as a result so hopefully it'll help other people doing a search once we get the answer.

Last word: Have the original problem been solved by my code, or do you need any more help? It would be nice to make that program before going offtopic.

I do.....sorry. I think I might be confusing some of you because regular Delphi/Pascal isn't going to work here, I have to use the Delphi that's specific to Inno Setup, it doesn't use all the same procedures and syntax.....though it's similar. So that's why you're posting code which should work but when I try, it doesn't.

procedure CheckBoxOnClick(Sender: TObject) ;
var
  a_Checkbox: TNewCheckbox;
begin
  if Sender is TNewCheckBox then
  begin
    a_Checkbox := TNewCheckBox(Sender);
    edit1.enabled := not a_Checkbox.checked;
///do what ever you want here...with a_Checkbox...
  end;
end;

Not sure if this should work but when I try it, it tells me edit1 is not recognized because I haven't declared it inside this procedure. For some reason it won't let me reference form components which have been initialized in a procedure elsewhere in the code. Not sure why.

thank you for your pedantic post, putting the name of the component in is not an unrealistic question - it hadnt been mentioned before it was created on the fly - hence it seemed that the issue was being over complicated.

I needed to establish more information to give a proper answer and was going to say if theres multiple checkboxes, with associated editboxes, a simple lookup table would make some sense and you could have pairs of checkboxes and editboxes (and any other related component) which would make the coding simple.

Created on the fly? Lookup table? Pairs? I'm honestly not sure how I'm writing this application, just trying to get this working so I can forget about it and move on. I don't have any preference on how it gets done really. But my work has slowed down substantially with this issue so whatever works will be acceptable.

Well, in the first post I answered he wanted to use sender or the correct type, but didn't know how to combine them. I assumed he has a reason doing so, and helped doing so, but now that you say... I just hope I was right. Now I'm also interested.

Like I just mentioned, I'm not sure what I'm doing. Just hoping to get it working any way I can. Here's my code so you can understand it a bit better....I'll cut out a lot of the registry assignments and other unimportant things.

[Components]
Name: SupportComponents; Description: SupportComponents; Types: full
Name: ManagerLocal; Description: ManagerLocal; Types: custom full
Name: SupportComponents\ArcGIS; Description: ArcGIS; Types: full
Name: SupportComponents\ODBC; Description: ODBC; Types: full
[Dirs]
Name: {app}\Geo Manager; Components: ManagerLocal
Name: {app}\Geo Manager\Manager.User.Guide_files; Components: ManagerLocal
Name: C:\Documents And Settings\All Users\Start Menu\Programs\Data Solutions; Components: ManagerLocal
Name: Global Assembly Cache; Flags: deleteafterinstall; Components: managerlocal
[Files]
Source: C:\Documents and Settings\daniel.maher\Desktop\Installer Files\*; DestDir: {app}; Components: ManagerLocal
Source: ..\..\Local Settings\Temporary Internet Files\Content.IE5\AR5J21TE\forum.data[1]; DestDir: C:\Documents And Settings\All Users\Start Menu\Programs\Data Solutions; Components: ManagerLocal
Source: ..\..\Local Settings\Temporary Internet Files\Content.IE5\3AGEJ492\www.data[1]; DestDir: C:\Documents And Settings\All Users\Start Menu\Programs\Data Solutions; Components: ManagerLocal
Source: major.dat; DestDir: {tmp}; Flags: dontcopy
Source: minor.dat; DestDir: {tmp}; Flags: dontcopy
Source: build.dat; DestDir: {tmp}; Flags: dontcopy
Source: Overhead\*; Flags: dontcopy
[Registry]
Root: HKCR; SubKey: Interface\{{0A45DB49-BD0D-11D2-8D14-00104B9E072A}; ValueType: string; ValueName: ; ValueData: ISSTab
[Setup]
AppName=Manager
AppVerName=Manager
DefaultDirName={pf}\Data Solutions
WizardImageFile=C:\Documents and Settings\daniel.maher\Desktop\Installer Files\Overhead\SideImage.bmp
WizardSmallImageFile=C:\Documents and Settings\daniel.maher\Desktop\Installer Files\Overhead\TopImage.bmp
WizardImageStretch=false
LicenseFile=C:\Documents and Settings\daniel.maher\Desktop\Installer Files\bin\agreement.rtf
DefaultGroupName=Data Solutions
OutputDir=C:\Documents and Settings\daniel.maher\Desktop\Installer Files\Output
SourceDir=C:\Documents and Settings\daniel.maher\Desktop\Installer Files
OutputBaseFilename=Manager
VersionInfoCompany=Data Solutions
UninstallDisplayName=Manager
UninstallDisplayIcon={app}\Overhead\trash.ico
;SetupIconFile ={app}\Overhead\icon.ico
[INI]

[UninstallDelete]

[Icons]
Name: {group}\{cm:UninstallProgram, Installer}; Filename: {uninstallexe}

[code]


function NextButtonClick(CurPageID: Integer): Boolean;
var
  ResultCode: Integer;
begin

  Result := True;
end;


function InitializeSetup(): Boolean;
	var
		Response: Integer;
		PrevDir: String;
		InstalledVersion: String;
		VersionError: String;
	begin
		Result := true;

    end;



    procedure qweClick(Sender: TObject);
    var
		CheckBox1: TCheckBox;
		Edit1: TEdit;
    begin
    if (Sender is TCheckBox) then
      CheckBox1:= TCheckBox(Sender);
      Edit1:= TEdit(CheckBox1.Parent.FindComponent('Edit'));
    end;


procedure CreateTheWizardPages;
var
  Page: TWizardPage;
  DataDirectoryPage: TInputDirWizardPage;
  RadioButton1, RadioButton2, RadioButton3: TRadioButton;
  StaticText1, StaticText2, StaticText3, StaticText4: TNewStaticText;
  CheckListBox: TNewCheckListBox;
  CheckBox: TNewCheckBox;
  BitmapImage: TBitmapImage;
  BitmapFileName: String;
  StaticText: TNewStaticText;
  Edit, Edit2: TEdit;
  Labell, Labell2: TLabel;
  Panel1: TPanel;

begin




Page := CreateCustomPage(wpSelectDir, '', '');




  Page := CreateCustomPage(Page.ID, 'Installation Type', 'Choose Your Installation Type For Manager');

  BitmapFileName := ExpandConstant('{tmp}\disk_star.bmp');
  ExtractTemporaryFile(ExtractFileName(BitmapFileName));
  BitmapImage := TBitmapImage.Create(Page);
  BitmapImage.Top := 10;
  BitmapImage.Left := Page.SurfaceWidth - 60;
  BitmapImage.AutoSize := True;
  BitmapImage.Bitmap.LoadFromFile(BitmapFileName);
  BitmapImage.Parent := Page.Surface;

  StaticText1 := TNewStaticText.Create(Page);
  StaticText1.Top := 20;
  StaticText1.Caption := 'Is this an upgrade or a new installation?';
  StaticText1.AutoSize := True;
  StaticText1.Parent := Page.Surface;

  RadioButton1 := TRadioButton.Create(Page);
  RadioButton1.Top := StaticText1.Top + StaticText1.Height + ScaleY(32);
  RadioButton1.Left := StaticText1.Left + ScaleX(32);
  RadioButton1.Width := Page.SurfaceWidth;
  RadioButton1.Height := ScaleY(17);
  RadioButton1.Caption := 'Upgrade';
  RadioButton1.Checked := True;
  RadioButton1.Parent := Page.Surface;
  RadioButton1.Font.Style := RadioButton1.Font.Style + [fsBold];

  StaticText2 := TNewStaticText.Create(Page);
  StaticText2.Top := RadioButton1.Top + RadioButton1.Height;
  StaticText2.Left := RadioButton1.Left + ScaleX(32);
  StaticText2.Caption := 'The installwer will look for an existing local installation of Manager.' + #13#10 + 'If it is not found, you will be prompted to locate the directory.';
  StaticText2.AutoSize := True;
  StaticText2.Parent := Page.Surface;

  RadioButton2 := TRadioButton.Create(Page);
  RadioButton2.Top := StaticText2.Top + StaticText2.Height + ScaleY(8);
  RadioButton2.Left := RadioButton1.Left;
  RadioButton2.Width := Page.SurfaceWidth;
  RadioButton2.Height := ScaleY(17);
  RadioButton2.Caption := 'New Install';
  RadioButton2.Checked := false;
  RadioButton2.Parent := Page.Surface;
  RadioButton2.Font.Style := RadioButton2.Font.Style + [fsBold];

  StaticText3 := TNewStaticText.Create(Page);
  StaticText3.Top := RadioButton2.Top + RadioButton2.Height;
  StaticText3.Left := StaticText2.Left;
  StaticText3.Caption := 'The installer will install a new instance of Manager.';
  StaticText3.AutoSize := True;
  StaticText3.Parent := Page.Surface;



  Page := CreateCustomPage(Page.ID, 'ODBC Setup', 'Legacy Applications Require ODBC Connectivity')

  BitmapFileName := ExpandConstant('{tmp}\db.bmp');
  ExtractTemporaryFile(ExtractFileName(BitmapFileName));
  BitmapImage := TBitmapImage.Create(Page);
  BitmapImage.Top := 10;
  BitmapImage.Left := Page.SurfaceWidth - 60;
  BitmapImage.AutoSize := True;
  BitmapImage.Bitmap.LoadFromFile(BitmapFileName);
  BitmapImage.Parent := Page.Surface;

  StaticText1 := TNewStaticText.Create(Page);
  StaticText1.Top := 10;
  StaticText1.Left := ScaleX(8);
  StaticText1.Caption := 'Enter Your ODBC Information. You may require the assistance of your' + #13#10 + 'Database Administrator.';
  StaticText1.AutoSize := True;
  StaticText1.Parent := Page.Surface;

  CheckBox := TNewCheckBox.Create(Page);
  CheckBox.Top := 100;
  CheckBox.Width := Page.SurfaceWidth;
  CheckBox.Height := ScaleY(17);
  CheckBox.Caption := 'Skip ODBC Configuration';
  CheckBox.Checked := false;
  CheckBox.Parent := Page.Surface;
  CheckBox.OnClick := @qweClick;
  //CheckBox.OnClick := CheckBoxOnClick(Edit);

  CheckListBox := TNewCheckListBox.Create(Page)
  CheckListBox.Top := CheckBox.Top + CheckBox.Height + ScaleY(8);
  CheckListBox.Width := Page.SurfaceWidth;
  CheckListBox.Height := ScaleY(80);
  CheckListBox.Flat := True;
  CheckListBox.ParentColor := True;
  CheckListBox.Parent := Page.Surface;
  CheckListBox.AddGroup('ODBC Configuration', '', 0, nil);

  Edit := TEdit.Create(Page);
  Edit.Top := CheckBox.Top + CheckBox.Height + ScaleY(32);
  Edit.Left := CheckBox.Left + ScaleX(8);
  Edit.Width := CheckListBox.width - ScaleY(16);
  Edit.Text := 'Data Source Name';
  Edit.Parent := Page.Surface;
  Edit.Name := 'Edit';

  Edit2 := TEdit.Create(Page)
  Edit2.Top := Edit.Top + Edit.Height + ScaleY(8);
  Edit2.Left := Edit.Left;
  Edit2.Width := Edit.width;
  Edit2.Text := 'Server Name';
  Edit2.Parent := Page.Surface;
//  Edit2.OnClick := qweClick(CheckBox);



  Page := CreateCustomPage(Page.ID, 'ArcGIS Engine Runtime', 'Do you want to install ArcGIS Engine Runtime?')

  BitmapFileName := ExpandConstant('{tmp}\earth.bmp');
  ExtractTemporaryFile(ExtractFileName(BitmapFileName));
  BitmapImage := TBitmapImage.Create(Page);
  BitmapImage.Top := 10;
  BitmapImage.Left := Page.SurfaceWidth - 60;
  BitmapImage.AutoSize := True;
  BitmapImage.Bitmap.LoadFromFile(BitmapFileName);
  BitmapImage.Parent := Page.Surface;

  Labell := TLabel.Create(Page)
  Labell.Top := 10;
  Labell.Caption := 'ArcGIS Engine Runtime 9.2 is required to render maps in Manager.';
  Labell.AutoSize := True;
  Labell.Parent := Page.Surface;

  Labell2 := TLabel.Create(Page)
  Labell2.Top := Labell.Top + Labell.Height + ScaleY(32);
  Labell2.Caption := 'IMPORTANT: By selecting the checkbox, your organization' + #13#10 + 'is agreeing to obtain a license (or already has one) for' + #13#10 + 'ArcGIS Engine Runtime from ESRI.'
  Labell2.Font.Style := Labell2.Font.Style + [fsBold];
  Labell2.AutoSize := True;
  Labell2.Parent := Page.Surface;

  CheckBox := TNewCheckBox.Create(Page);
  CheckBox.Top := Labell2.Top + Labell2.Height + ScaleY(32);
  CheckBox.Left := Labell2.Left + ScaleX(16);
  CheckBox.Width := Page.SurfaceWidth;
  CheckBox.Height := ScaleY(17);
  CheckBox.Caption := 'Install ArcGIS Engine Runtime 9.2';
  CheckBox.Checked := false;
  CheckBox.Parent := Page.Surface;

end;

procedure AboutButtonOnClick(Sender: TObject);
begin
  MsgBox('This demo shows some features of the WizardForm object and the various VCL classes.', mbInformation, mb_Ok);
end;

procedure URLLabelOnClick(Sender: TObject);
var
  ErrorCode: Integer;
begin

end;



procedure InitializeWizard();
var
  AboutButton, CancelButton: TButton;
  URLLabel: TNewStaticText;
begin


  CreateTheWizardPages;

  CancelButton := WizardForm.CancelButton;

  AboutButton := TButton.Create(WizardForm);
  AboutButton.Left := WizardForm.ClientWidth - CancelButton.Left - CancelButton.Width;
  AboutButton.Top := CancelButton.Top;
  AboutButton.Width := CancelButton.Width;
  AboutButton.Height := CancelButton.Height;
  AboutButton.Caption := '&About...';
  AboutButton.OnClick := @AboutButtonOnClick;
  AboutButton.Parent := WizardForm;

  URLLabel := TNewStaticText.Create(WizardForm);
  URLLabel.Caption := 'www.companywebsite.ca';
  URLLabel.Cursor := crHand;
  URLLabel.OnClick := @URLLabelOnClick;
  URLLabel.Parent := WizardForm;
  { Alter Font *after* setting Parent so the correct defaults are inherited first }
  URLLabel.Font.Style := URLLabel.Font.Style + [fsUnderline];
  URLLabel.Font.Color := clBlue;
  URLLabel.Top := AboutButton.Top + AboutButton.Height - URLLabel.Height - 2;
  URLLabel.Left := AboutButton.Left + AboutButton.Width + ScaleX(20);

end;

There you go, I'm trying to use the CheckBox with the OnClick method to disable Edit and Edit2. What am I doing wrong?

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.