I want to detect when user press the Tab key in setup (e.g. when focus is being changed from one control to another).
Here is my code, but the MsgBox is never executed.
What am I doing wrong?
[Code]
procedure OnKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
MsgBox('Hello.', mbInformation, MB_OK);
end;
procedure OnKeyPress(Sender: TObject; var Key: Char);
begin
MsgBox('Hello.', mbInformation, MB_OK);
end;
procedure OnKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
MsgBox('Hello.', mbInformation, MB_OK);
end;
procedure InitializeWizard();
begin
MainForm.OnKeyDown := #OnKeyDown;
MainForm.OnKeyPress := #OnKeyPress;
MainForm.OnKeyUp := #OnKeyUp;
end;
You should use WizardForm instead of MainForm and also set the KeyPreView to true:
procedure InitializeWizard();
begin
WizardForm.OnKeyDown := #OnKeyDown;
WizardForm.OnKeyPress := #OnKeyPress;
WizardForm.OnKeyUp := #OnKeyUp;
WizardForm.KeyPreview:=true;
end;
But I'm not sure if it catches Virtual Keys.
Related
I have created some custom checkboxes in the finished page of Inno Setup.
For example launching an app, opening a text file etc.
I need when the user clicks on the finish button I check those checkboxes and do whatever that is needed. How can I do such a thing in Inno Setup?
Here is the code:
procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = wpFinished then
begin
Launch := TNewCheckBox.Create(WizardForm);
Launch.Parent := WizardForm;
Launch.Left := WizardForm.ClientWidth - 350;
Launch.Top := WizardForm.CancelButton.Top;
Launch.Width := 120;
Launch.Height := WizardForm.CancelButton.Height;
Launch.Caption := 'Launch';
end;
end;
In NextButtonClick event handler, test if your checkbox is checked and act accordingly.
function NextButtonClick(CurPageID: Integer): Boolean;
var
ResultCode: Integer;
Path: string;
Message: string;
begin
if CurPageID = wpFinished then
begin
if Launch.Checked then
begin
Path := ExpandConstant('{app}\MyProg.exe');
if ExecAsOriginalUser(Path, '', '', SW_SHOW, ewNoWait, ResultCode) then
begin
Log('Executed MyProg');
end
else
begin
Message := 'Error executing MyProg: ' + SysErrorMessage(ResultCode);
MsgBox(Message, mbError, MB_OK);
end;
end;
end;
Result := True;
end;
Simply check the checkbox state:
if (Launch.Checked = True) then
begin
// checkbox is checked
end
else
begin
// Checkbox is unchecked
end;
The best place is to use function NextButtonClick(CurPageID: Integer): Boolean;
however in that case you need to make your checkbox a global variable (so it is accessible).
The below code asks user to select Yes or No using CreateInputOptionPage, with the below code I want to prompt message "Yes selected" if user selects "Yes" if user selects no then prompt "No selected".
My code doesn't seem to work. Please help.
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
DisableProgramGroupPage=yes
UninstallDisplayIcon={app}\MyProg.exe
OutputDir=D:\authorized\Builds\Custom wizard
[Code]
//#include "Solo - detectVersionFInal.iss"
var
UsagePage: TInputOptionWizardPage;
InstallationTypeIsClient: boolean;
Initialize:boolean;
procedure InitializeWizard;
begin
{ Create the pages }
UsagePage := CreateInputOptionPage(wpWelcome,
'KMOffline setup information', 'How would you like to install KMOffline?',
'Would you like to insall KMOffline as a service?.',
True, False);
UsagePage.Add('Yes');
UsagePage.Add('No');
UsagePage.Values[0] := False;
end;
function NextButtonClick(CurPageID: Integer): Boolean;
begin
if CurPageID=UsagePage.ID then
begin
InstallationTypeIsClient := UsagePage.Values[0];
MsgBox('InstallationTypeIsClient value is ' + Format('%d', [InstallationTypeIsClient]), mbInformation, MB_OK);
end;
Result := True;
end;
function InitializeSetup: Boolean;
var
begin
if (InstallationTypeIsClient=True) then
begin
MsgBox('Yes selected' + Format('%d', [InstallationTypeIsClient]), mbInformation, MB_OK);
end;
if (InstallationTypeIsClient=False) then
begin
MsgBox('No selected ' + Format('%d', [InstallationTypeIsClient]), mbInformation, MB_OK);
end;
Result := True;
end;
Just move your code from InitializeSetup to NextButtonClick:
function NextButtonClick(CurPageID: Integer): Boolean;
begin
if CurPageID = UsagePage.ID then
begin
if UsagePage.Values[0] then
begin
MsgBox('Yes selected', mbInformation, MB_OK);
end
else
begin
MsgBox('No selected', mbInformation, MB_OK);
end;
end;
Result := True;
end;
I have a small Windows software created with Delphi 7 where a thread periodically do some action, like save information in a SQLite database. It works just fine, but the same thread never execute when Windows is about to shutdown/reboot/logoff. Here is a simple example:
type
TSaveText = class(TThread)
private
FText: string;
protected
procedure Execute; override;
end;
...
private
procedure WMQueryEndSession(var AMsg: TMessage); message WM_QUERYENDSESSION;
procedure SaveText(const AText: string);
...
procedure AddToLog(const Str: string);
var
Pth: string;
Txt: TextFile;
begin
Pth := ExtractFilePath(ParamStr(0)) + 'log.txt';
try
AssignFile(Txt, Pth);
if not FileExists(Pth) then
ReWrite(Txt);
Append(Txt);
WriteLn(Txt, Trim(Str));
finally
CloseFile(Txt);
end;
end;
procedure TfrmMain.SaveText(const AText: String);
begin
with TSaveText.Create(True) do
begin
FText := AText;
FreeOnTerminate := True;
Priority := tpNormal;
Resume;
end;
end;
procedure TSaveText.Execute;
begin
inherited;
AddToLog(FText);
end;
procedure TfrmMain.WMQueryEndSession(var AMsg: TMessage);
begin
inherited;
SaveText('Windows is about to shutdown/reboot/logoff!');
AMsg.Result := 1;
end;
In this example, the text 'Windows is about to shutdown/reboot/logoff!' is never saved in the log file. But if I remove the action from the thread, it works:
procedure TfrmMain.WMQueryEndSession(var AMsg: TMessage);
begin
inherited;
AddToLog('Windows is about to shutdown/reboot/logoff!');
AMsg.Result := 1;
end;
I'd like to know if there is a way to force thread to execute in this scenario, when Windows is about to shutdown/reboot/logoff.
Thanks!
I found a code here that I needed. To only allow write numbers in a text box. But I still wanted more, which does not offer up the "Next" button without write the number in this text box.
Can help me?
procedure NumbersOnly(Sender: TObject; var Key: Char);
var
S: string;
begin
S := ('1234567890'#8);
if Pos(Key, S) = 0 then
Key := #0;
end;
You can setup the next button to be enabled or disabled in the CurPageChanged event when the user reaches the page where resides your edit box. Except that you need to monitor changes of that edit box to enable or disable the next button according to whether there's something entered in that edit box. For this you need to write a handler for the OnChange event. Here is an example:
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
[Code]
var
MyEdit: TNewEdit;
MyPage: TWizardPage;
procedure MyEditChange(Sender: TObject);
begin
{ enable the next button if the edit box is not empty; disable otherwise }
WizardForm.NextButton.Enabled := MyEdit.Text <> '';
end;
procedure MyEditKeyPress(Sender: TObject; var Key: Char);
var
KeyCode: Integer;
begin
{ allow only numbers }
KeyCode := Ord(Key);
if not ((KeyCode = 8) or ((KeyCode >= 48) and (KeyCode <= 57))) then
Key := #0;
end;
procedure InitializeWizard;
begin
MyPage := CreateCustomPage(wpWelcome, 'Caption', 'Description');
MyEdit := TNewEdit.Create(WizardForm);
MyEdit.Parent := MyPage.Surface;
MyEdit.Left := 0;
MyEdit.Top := 0;
MyEdit.Width := 150;
MyEdit.OnChange := #MyEditChange;
MyEdit.OnKeyPress := #MyEditKeyPress;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
{ if the currently turned wizard page is the one with the edit box, enable }
{ the next button if the edit box is not empty; disable otherwise }
if CurPageID = MyPage.ID then
WizardForm.NextButton.Enabled := MyEdit.Text <> '';
end;
There are two flaws in the #TLama's answer:
A user can bypass the check by using Paste command from edit box context menu (and possibly by other kinds of input methods).
To fix this, you can introduce a last resort check in NextButtonClick.
I would also suggest adding the check for an empty input there, instead of MyEditChange, as it allows providing feedback to the user, explaining what is wrong.
On the other hand, Ctrl+C, Ctrl+V and Ctrl+X keys are not working. Particularly a lack of Ctrl+V is not comfortable.
To fix this, allow these control characters in the MyEditKeyPress.
[Code]
var
MyEdit: TNewEdit;
MyPage: TWizardPage;
procedure ValidateMyEdit;
begin
{ enable the next button if the edit box is not empty; disable otherwise }
WizardForm.NextButton.Enabled := (MyEdit.Text <> '');
end;
procedure MyEditChange(Sender: TObject);
begin
ValidateMyEdit;
end;
function IsDigit(C: Char): Boolean;
begin
Result := (C >= '0') and (C <= '9')
end;
procedure MyEditKeyPress(Sender: TObject; var Key: Char);
begin
if not ((Key = #8) or { Tab key }
(Key = #3) or (Key = #22) or (Key = #24) or { Ctrl+C, Ctrl+V, Ctrl+X }
IsDigit(Key)) then
begin
Key := #0;
end;
end;
procedure InitializeWizard;
begin
MyPage := CreateCustomPage(wpWelcome, 'Caption', 'Description');
MyEdit := TNewEdit.Create(WizardForm);
MyEdit.Parent := MyPage.Surface;
MyEdit.Left := 0;
MyEdit.Top := 0;
MyEdit.Width := 150;
MyEdit.OnChange := #MyEditChange;
MyEdit.OnKeyPress := #MyEditKeyPress;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = MyPage.ID then
begin
ValidateMyEdit;
end;
end;
function NextButtonClick(CurPageID: Integer): Boolean;
var
I: Integer;
begin
Result := True;
if CurPageID = MyPage.ID then
begin
for I := 1 to Length(MyEdit.Text) do
begin
if not IsDigit(MyEdit.Text[I]) then
begin
MsgBox('Only numbers are allowed', mbError, MB_OK);
Result := False;
Break;
end;
end;
end;
end;
This is the way I use based on keys from ASCII code:
procedure justNumbers(Sender: TObject; var Key: Char);
begin
if not ((Key = #8) or (Key = #43) or ((Key >= #48) and (Key <= #57)))
then
begin
Key := #0;
end;
end;
Could work for validate others characters too.
I'm trying to override Next/Cancel buttons on wpFinished page - NextButton should show downloaded file and exit the installator - it's working ok but CancelButton doesn't do nothing - it should close the installator with standard confirm. I wonder it is possible with standard inno events or I need to write own code to exit the application and show the confirm?
function NextButtonClick(CurPage: Integer): Boolean;
begin
if CurPage = wpFinished then begin
ShowDownloadedFile();
end;
Result := True;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = wpFinished then begin
WizardForm.NextButton.Caption := SetupMessage(msgButtonInstall);
WizardForm.CancelButton.Caption := SetupMessage(msgButtonFinish);
WizardForm.CancelButton.Visible := True;
end;
end;
Here it is, but don't do this at home kids :-)
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
[Code]
procedure ExitProcess(uExitCode: UINT);
external 'ExitProcess#kernel32.dll stdcall';
function NextButtonClick(CurPage: Integer): Boolean;
begin
Result := True;
// if the fake Finish button was clicked...
if CurPage = wpFinished then
MsgBox('Welcome to the next installation!', mbInformation, MB_OK);
end;
procedure CancelButtonClickFinishedPage(Sender: TObject);
begin
// display the "Exit Setup ?" message box and if the user selects "Yes",
// then exit the process; it is currently the only way how to exit setup
// process manually
if ExitSetupMsgBox then
ExitProcess(0);
end;
procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = wpFinished then
begin
WizardForm.NextButton.Caption := SetupMessage(msgButtonInstall);
WizardForm.CancelButton.Caption := SetupMessage(msgButtonFinish);
WizardForm.CancelButton.Visible := True;
// bind your own OnClick event for the Cancel button; the original one
// is already disconnected at this stage
WizardForm.CancelButton.OnClick := #CancelButtonClickFinishedPage;
end;
end;
The proper alternative to what you're trying to do is to include a [Run] entry like so:
[Run]
Filename: {app}\yourfile.exe; Description: Run my application; Flags: postinstall nowait
This will display a checkbox on the wpFinished page giving them the choice to run the app or not.