954,529 Members — Technology Publication meets Social Media
Username:
Password:
Lost login information?
Have something to say? Contribute New Article Reply to this Article

How do I disable form controls?

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.

Deemar
Newbie Poster
20 posts since Aug 2008
Reputation Points: 10
Solved Threads: 0
 

Something.Enabled:=false;

LizR
Posting Virtuoso
1,791 posts since Aug 2008
Reputation Points: 196
Solved Threads: 190
 

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

Deemar
Newbie Poster
20 posts since Aug 2008
Reputation Points: 10
Solved Threads: 0
 

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?

Deemar
Newbie Poster
20 posts since Aug 2008
Reputation Points: 10
Solved Threads: 0
 

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..

LizR
Posting Virtuoso
1,791 posts since Aug 2008
Reputation Points: 196
Solved Threads: 190
 

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.

MoZo1
Junior Poster
119 posts since Mar 2008
Reputation Points: 43
Solved Threads: 4
 

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

LizR
Posting Virtuoso
1,791 posts since Aug 2008
Reputation Points: 196
Solved Threads: 190
 

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.

Deemar
Newbie Poster
20 posts since Aug 2008
Reputation Points: 10
Solved Threads: 0
 
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.)

MoZo1
Junior Poster
119 posts since Mar 2008
Reputation Points: 43
Solved Threads: 4
 

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
Deemar
Newbie Poster
20 posts since Aug 2008
Reputation Points: 10
Solved Threads: 0
 

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..

LizR
Posting Virtuoso
1,791 posts since Aug 2008
Reputation Points: 196
Solved Threads: 190
 
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.

MoZo1
Junior Poster
119 posts since Mar 2008
Reputation Points: 43
Solved Threads: 4
 

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.

Deemar
Newbie Poster
20 posts since Aug 2008
Reputation Points: 10
Solved Threads: 0
 

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.

LizR
Posting Virtuoso
1,791 posts since Aug 2008
Reputation Points: 196
Solved Threads: 190
 

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.

MoZo1
Junior Poster
119 posts since Mar 2008
Reputation Points: 43
Solved Threads: 4
 

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

LizR
Posting Virtuoso
1,791 posts since Aug 2008
Reputation Points: 196
Solved Threads: 190
 

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......

Deemar
Newbie Poster
20 posts since Aug 2008
Reputation Points: 10
Solved Threads: 0
 

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;
LizR
Posting Virtuoso
1,791 posts since Aug 2008
Reputation Points: 196
Solved Threads: 190
 

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.

Deemar
Newbie Poster
20 posts since Aug 2008
Reputation Points: 10
Solved Threads: 0
 

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.

LizR
Posting Virtuoso
1,791 posts since Aug 2008
Reputation Points: 196
Solved Threads: 190
 

This question has already been solved

Post: Markdown Syntax: Formatting Help
You