Inno Setup Set TInputQueryWizardPage Height - height

I have installation script that is using TInputQueryWizardPage. How can I increase height of this page? For example if I have this...
procedure InitializeWizard;
begin
MyPage := CreateInputQueryPage(wpReady,
'Some Information', 'Enter Information',
'Enter information, then click Next.');
MyPage.Add('info1', False);
MyPage.Add('info2', False);
MyPage.Add('info3', False);
MyPage.Add('info4', False);
MyPage.Add('info5', False);
MyPage.Values[0] := GetPreviousData('info1', '');
MyPage.Values[1] := GetPreviousData('info2', '');
MyPage.Values[2] := GetPreviousData('info3', '');
MyPage.Values[3] := GetPreviousData('info4', '');
MyPage.Values[4] := GetPreviousData('info5', '');
end;
...then last edit box is not visible because it cannot fit on the form.
Thank you for your time

Since the wizard pages themselves don't support scroll bars and there is no container control with scroll bar support, I would suggest you to shift those edit fields with their corresponding labels upward. You're having 5 of them which is a maximum which looks fine for me if you display a subcaption, what you seem to do. The following script shows how to shift those items upward by the amount of pixels specified in the OffsetPixels constant:
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
[Code]
const
OffsetPixels = 11;
var
MyPage: TInputQueryWizardPage;
procedure OffsetPageItem(Page: TInputQueryWizardPage; Index,
Offset: Integer);
begin
Page.Edits[Index].Top := Page.Edits[Index].Top + Offset;
Page.PromptLabels[Index].Top := Page.PromptLabels[Index].Top +
Offset;
end;
procedure InitializeWizard;
var
Index: Integer;
begin
MyPage := CreateInputQueryPage(wpWelcome, 'Caption',
'Description', 'SubCaption');
Index := MyPage.Add('info1', False);
Index := MyPage.Add('info2', False);
OffsetPageItem(MyPage, Index, -Index * OffsetPixels);
Index := MyPage.Add('info3', False);
OffsetPageItem(MyPage, Index, -Index * OffsetPixels);
Index := MyPage.Add('info4', False);
OffsetPageItem(MyPage, Index, -Index * OffsetPixels);
Index := MyPage.Add('info5', False);
OffsetPageItem(MyPage, Index, -Index * OffsetPixels);
end;
And a screenshot:

Related

How do I combine FreeArc compression with Inno Setup? [duplicate]

I've been trying to make an installer by Inno Setup which only supports zip/bzip/lzma/lzma2 compression methods. I packed my archive by FreeArc (output file extension is .arc but renamed it to .bin) but Inno Setup is not able to extract it. I searched on internet how to implant arc decompression into Inno Setup but all sites refer to FreeArc official website which is dead for a while.
All I need is the code to use the necessary dll files to give Inno Setup the ability to decompress arc archives plus the list of those dll files needed to do so.
I appreciate any help.
This answer has been superseded by Inno Setup - How to add cancel button to decompressing page? that uses unarc.dll instead of driving the console Arc.exe.
I'm keeping this answer, as its concept can be useful for other archive types.
See the example below. It:
takes an ARC file, embeds it to the installer
during installation, the ARC file is extracted to a temporary folder
the files from the ARC file is extracted to the target folder
#define ArcArchive "test.arc"
[Files]
Source: {#ArcArchive}; DestDir: "{tmp}"; Flags: nocompression deleteafterinstall
Source: Arc.exe; Flags: dontcopy
[Code]
function BufferToAnsi(const Buffer: string): AnsiString;
var
W: Word;
I: Integer;
begin
SetLength(Result, Length(Buffer) * 2);
for I := 1 to Length(Buffer) do
begin
W := Ord(Buffer[I]);
Result[(I * 2)] := Chr(W shr 8); // high byte
Result[(I * 2) - 1] := Chr(Byte(W)); // low byte
end;
end;
function SetTimer(
Wnd: LongWord; IDEvent, Elapse: LongWord; TimerFunc: LongWord): LongWord;
external 'SetTimer#user32.dll stdcall';
function KillTimer(hWnd: LongWord; uIDEvent: LongWord): BOOL;
external 'KillTimer#user32.dll stdcall';
var
ProgressPage: TOutputProgressWizardPage;
ProgressFileName: string;
procedure UpdateProgressProc(
H: LongWord; Msg: LongWord; Event: LongWord; Time: LongWord);
var
S: AnsiString;
L: Integer;
P: Integer;
Max: Integer;
Progress: string;
Buffer: string;
Stream: TFileStream;
Percent: Integer;
Found: Boolean;
begin
Found := False;
if not FileExists(ProgressFileName) then
begin
Log(Format('Progress file %s does not exist', [ProgressFileName]));
end
else
begin
try
// Need shared read as the output file is locked for writting,
// so we cannot use LoadStringFromFile
Stream :=
TFileStream.Create(ProgressFileName, fmOpenRead or fmShareDenyNone);
try
L := Stream.Size;
Max := 100*2014;
if L > Max then
begin
Stream.Position := L - Max;
L := Max;
end;
SetLength(Buffer, (L div 2) + (L mod 2));
Stream.ReadBuffer(Buffer, L);
S := BufferToAnsi(Buffer);
finally
Stream.Free;
end;
if S = '' then
begin
Log(Format('Progress file %s is empty', [ProgressFileName]));
end;
except
Log(Format('Failed to read progress from file %s - %s', [
ProgressFileName, GetExceptionMessage]));
end;
end;
if S <> '' then
begin
P := Pos('Extracted', S);
if P > 0 then
begin
Log('Extraction done');
Percent := 100;
Found := True;
end
else
begin
P := Pos('%', S);
if P > 0 then
begin
repeat
Progress := Copy(S, 1, P - 1);
Delete(S, 1, P);
P := Pos('%', S);
until (P = 0);
P := Length(Progress);
while (P > 0) and
(((Progress[P] >= '0') and (Progress[P] <= '9')) or
(Progress[P] = '.')) do
begin
Dec(P);
end;
Progress := Copy(Progress, P + 1, Length(Progress) - P);
P := Pos('.', Progress);
if P > 0 then
begin
Progress := Copy(Progress, 1, P - 1);
end;
Percent := StrToInt(Progress);
Log(Format('Percent: %d', [Percent]));
Found := True;
end;
end;
end;
if not Found then
begin
Log('No new data found');
// no new progress data, at least pump the message queue
ProgressPage.SetProgress(ProgressPage.ProgressBar.Position, 100);
end
else
begin
ProgressPage.SetProgress(Percent, 100);
ProgressPage.SetText(Format('Extracted: %d%%', [Percent]), '');
end;
end;
procedure ExtractArc;
var
ArcExtracterPath: string;
ArcArchivePath: string;
TempPath: string;
CommandLine: string;
Timer: LongWord;
ResultCode: Integer;
S: AnsiString;
Message: string;
begin
ExtractTemporaryFile('Arc.exe');
ProgressPage :=
CreateOutputProgressPage('Decompression', 'Decompressing archive...');
ProgressPage.SetProgress(0, 100);
ProgressPage.Show;
try
Timer := SetTimer(0, 0, 250, CreateCallback(#UpdateProgressProc));
TempPath := ExpandConstant('{tmp}');
ArcExtracterPath := TempPath + '\Arc.exe';
ArcArchivePath := TempPath + '\{#ArcArchive}';
ProgressFileName := ExpandConstant('{tmp}\progress.txt');
Log(Format('Expecting progress in %s', [ProgressFileName]));
CommandLine :=
Format('"%s" x -y -o+ -dp"%s" "%s" > "%s"', [
ArcExtracterPath, ExpandConstant('{app}'), ArcArchivePath,
ProgressFileName]);
Log(Format('Executing: %s', [CommandLine]));
CommandLine := Format('/C "%s"', [CommandLine]);
if not Exec(ExpandConstant('{cmd}'), CommandLine, '', SW_HIDE,
ewWaitUntilTerminated, ResultCode) then
begin
RaiseException('Cannot start extracter');
end
else
if ResultCode <> 0 then
begin
LoadStringFromFile(ProgressFileName, S);
Message :=
Format('Arc extraction failed failed with code %d', [ResultCode]);
Log(Message);
Log('Output: ' + S);
RaiseException(Message);
end
else
begin
Log('Arc extraction done');
end;
finally
// Clean up
Log('Arc extraction cleanup');
KillTimer(0, Timer);
ProgressPage.Hide;
DeleteFile(ProgressFileName);
end;
Log('Arc extraction end');
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssPostInstall then
begin
ExtractArc;
end;
end;
The code needs arc.exe (I've taken it from PeaZip portable package).
For CreateCallback function, you need Inno Setup 6. If you are stuck with Inno Setup 5, you can use WrapCallback function from InnoTools InnoCallback library (and you need Unicode version of Inno Setup 5).
Alternatively, to avoid double extraction, you can distribute the arc file along the installer.
Just use {src} to resolve its path:
ArcArchivePath := ExpandConstant('{src}\{#ArcArchive}');
And remove the {#ArcArchive} entry from the [Files] section.
It would be more robust to implement the extraction using unarc.dll, like seen in the FreeArc+InnoSetup package ISFreeArcExtract v.4.0.rar.
Freearc Actually Comes with Inno Extraction Example
http://freearc2.azurewebsites.net/InnoSetup.aspx

FireMonkey drawing with tPath does not fill the shape

I want to use a TPathData to draw shapes and fill them with an arbitrary color. I'm using the following code, at Button1Click, wich I extracted from a sample at Embarcadero documentation:
procedure TformPathDrawing.Button1Click(Sender: TObject);
var path: TPathData;
begin
Image1.Bitmap.Canvas.Fill.Color := TAlphaColorRec.Blue;
path := TPathData.Create;
path.Data := 'M 01,00 L 02,01 L 01,02 L 00,01 L 01,00';
Image1.Bitmap.Clear ($FFFFFF);
Image1.Bitmap.Canvas.BeginScene;
Image1.Bitmap.Canvas.FillPath (path, 200);
Image1.Bitmap.Canvas.EndScene;
end;
When this code is executed, as expected, a romboid is rendered, but it is not filled up with the color set in the first command. Anyone knows what is wrong? Thanks.
Here is right code. You can find another details in FMX.Objects.pas procedure TCustomPath.UpdateCurrent and other; or just Debug TPath visual component.
{aPath - is vector path of image;
aStretch - how to draw vector data - true - stretch draw, false = fit to bitmap
aBitmap - must be created. In bitmap you should specify:
Width, Height, Bitmap.Canvas.Fill.Color, Bitmap.Canvas.Stroke.Color
and, if you need, another drawing stuff like Gradient, stroke thikness,
background texture) }
procedure TForm1.DrawVectorPath(const aPath: string; aBitmap: TBitmap; aStretch: boolean);
var
vPath: TPathData;
R: TRectF;
begin
Assert(aBitmap <> nil);
vPath := TPathData.Create;
try
vPath.Data := aPath;
aBitmap.Clear($FFFFFF);
if aStretch then
begin
R := vPath.GetBounds;
vPath.Translate(-R.Left, -R.Top);
vPath.Scale(aBitmap.Width / R.Width, aBitmap.Height / R.Height);
end
else // Fit image
begin
R := TRect.Create(0, 0, aBitmap.Width, aBitmap.Height);
vPath.FitToRect(R);
end;
aBitmap.Canvas.BeginScene;
aBitmap.Canvas.FillPath(vPath, 1);
aBitmap.Canvas.DrawPath(vPath, 1);
aBitmap.Canvas.EndScene;
finally
vPath.Free;
end;
end;
Because comments can't have code (at least not formatted). Here is my code, that works.
procedure TForm7.RadioButton6Click(Sender: TObject);
var path: TPathData;
begin
Image1.Bitmap.Canvas.Fill.Color := TAlphaColorRec.Blue;
Image1.Bitmap.Canvas.Stroke.Color := TAlphaColorRec.black;
path := TPathData.Create;
try
path.Data := 'M 01,00 L 20,01 L 10,20 L 00,10 L 01,00';
Image1.Bitmap.Clear ($FFFFFF);
Image1.Bitmap.Canvas.BeginScene;
Image1.Bitmap.Canvas.FillPath (path, 200);
Image1.Bitmap.Canvas.EndScene;
finally
path.Free;
end;
end;
Note that the stroke color is set as well. That's the only difference I can make out here.
Follows code that works (in my case):
procedure TformPathDrawing.Button1Click(Sender: TObject);
begin
Image1.Bitmap.Canvas.Fill.Color := TAlphaColorRec.Blue;
path.Clear;
path.Data := 'M 01,00 L 02,01 L 01,02 L 00,01 L 01,00';
Image1.Bitmap.Canvas.BeginScene;
Image1.Bitmap.Canvas.FillPath (path, 1);
Image1.Bitmap.Canvas.EndScene;
end;
In my code, variable path is created outside the painting code. Since path.Data; is additive, it is mandatory, before adding the current path.Data;, to place a path.Clear; statement, to clean out whatever remains into the point array. Hope this help other people.

GetSaveFileName fails with CDERR_FINDRESFAILURE

I've written a TOpenPictDialog (source code see below) component, which finally fails under certain circumstands when calling
Result := TDialogFunc(DialogFunc)(DialogData);
in Dialogs.pas. As DialogFunc correctly points to GetOpenFileName I call CommDlgExtendedError afterwards for test to find out what's wrong. It returns CDERR_FINDRESFAILURE. In this case the dialog is simply not showing. My test form only contains a button and the TOpenPictDialog component, when pressing the button, OpenPictDialog1->Execute is called - that's all.
The very strange thing is that it does work perfectly (besides of the TListView flickering on resize) under one of the following circumstands:
a) add ExtDlgs in "uses" in calling form
b) add an original TOpenPictureDialog to the form without calling it
c) adding the PAS file containing TOpenPictDialog to the project (although TOpenPictDialog has been already installed)
If I write a C++ Builder application with the one calling form I never get TOpenPictDialog working (even if I add the additional TOpenPictureDialog component).
unit PictureDlg;
{$R-,H+,X+}
{$IF CompilerVersion > 23} {$DEFINE GE_DXE2} {$IFEND}
interface
{$IFDEF GE_DXE2}
uses Winapi.Messages, Winapi.Windows, System.SysUtils, System.Classes, Vcl.Controls, Vcl.StdCtrls,
Vcl.Graphics, Vcl.ExtCtrls, Vcl.Buttons, Vcl.Dialogs, Vcl.ExtDlgs, Vcl.Consts, Vcl.ComCtrls;
{$ELSE}
uses Messages, Windows, SysUtils, Classes, Controls, StdCtrls,
Graphics, ExtCtrls, Buttons, Dialogs, ExtDlgs, Consts, ComCtrls;
{$ENDIF}
(*$HPPEMIT '// Alias records for C++ code that cannot compile in STRICT mode yet.' *)
(*$HPPEMIT '#if defined(_VCL_ALIAS_RECORDS)' *)
(*$HPPEMIT '#if !defined(STRICT)' *)
// (*$HPPEMIT ' #pragma alias "#Vcl#Extdlgs#TOpenPictDialog#Execute$qqrpv"="#Vcl#Extdlgs#TOpenPictDialog#Execute$qqrp6HWND__"' *)
(*$HPPEMIT '#endif' *)
(*$HPPEMIT '#endif' *)
type
{ TOpenPictDialog }
TOpenPictDialog = class(TOpenDialog)
private
FListView: TListView;
FTopLabel, FBottomLabel: TStaticText;
FImageCtrl: TImage;
FSavedFilename: string;
FOldDialogWndProc: Pointer;
FDialogMethodInstance: Pointer;
FDialogHandle: THandle;
function IsFilterStored: Boolean;
procedure DialogWndProc(var Msg: TMessage);
protected
procedure DoClose; override;
procedure DoSelectionChange; override;
procedure DoShow; override;
function TaskModalDialog(DialogFunc: Pointer; var DialogData): Bool; override;
published
property Filter stored IsFilterStored;
public
constructor Create(AOwner: TComponent); override;
function Execute(ParentWnd: HWND): Boolean; override;
property DialogListView: TListView read FListView;
property DialogImage: TImage read FImageCtrl;
property TopLabel: TStaticText read FTopLabel;
property BottomLabel: TStaticText read FBottomLabel;
end;
procedure Register;
implementation
uses
{$IFDEF GE_DXE2}
{$IF DEFINED(CLR)}
System.Runtime.InteropServices, System.Reflection, System.Security.Permissions, System.IO,
{$IFEND}
System.Math, Vcl.Forms, Winapi.CommDlg, Winapi.Dlgs, System.Types, Winapi.ShlObj, Winapi.ActiveX;
{$ELSE}
{$IF DEFINED(CLR)}
InteropServices, Reflection, Permissions, IO,
{$IFEND}
Math, Forms, CommDlg, Dlgs, Types, ShlObj, ActiveX;
{$ENDIF}
{ TOpenPictDialog }
constructor TOpenPictDialog.Create(AOwner: TComponent);
begin
FDialogHandle := 0;
FDialogMethodInstance := NIL;
inherited Create(AOwner);
Filter := GraphicFilter(TGraphic);
FListView := TListView.Create(Self);
FImageCtrl := TImage.Create(Self);
with FListView do
begin
Name := 'ListView';
SetBounds(204, 5, 169, 200);
BevelOuter := bvNone;
BorderWidth := 6;
TabOrder := 1;
Color := clWindow;
ParentDoubleBuffered := false;
DoubleBuffered := true;
OwnerDraw := true;
Ctl3D := true;
with FImageCtrl do
begin
Picture := nil;
Name := 'Image';
Parent := FListView;
end;
end;
FTopLabel := TStaticText.Create(Self);
with FTopLabel do
begin
Name := 'TopLabel';
SetBounds(6, 6, 157, 23);
AutoSize := False;
Caption := 'Preview:';
end;
FBottomLabel := TStaticText.Create(Self);
with FBottomLabel do
begin
Name := 'BottomLabel';
SetBounds(6, 6, 157, 23);
AutoSize := False;
Caption := 'Image size: 208 x 149 px';
Alignment := taCenter;
end;
end;
procedure TOpenPictDialog.DialogWndProc(var Msg: TMessage);
var
PreviewRect, ListViewRect, WindowRect, LabelRect: TRect;
WndControl: HWND;
begin
Msg.Result := CallWindowProc(FOldDialogWndProc, FDialogHandle, Msg.Msg, Msg.WParam, Msg.LParam);
if ((Msg.Msg = WM_WINDOWPOSCHANGED) and
((TWMWindowPosMsg(Msg).WindowPos.Flags and SWP_NOSIZE) = 0)) or
(Msg.Msg = WM_SHOWWINDOW) then begin
PreviewRect := FListView.BoundsRect;
GetWindowRect(Handle, WindowRect);
WndControl := FindWindowEx(FDialogHandle, 0, 'SHELLDLL_DefView', nil);
WndControl := FindWindowEx(WndControl, 0, 'SysListView32', nil);
if WndControl <> 0 then begin
GetWindowRect(WndControl, ListViewRect);
PreviewRect.Top := ListViewRect.Top - WindowRect.Top;
PreviewRect.Bottom := PreviewRect.Top + ListViewRect.Bottom - ListViewRect.Top;
if (not EqualRect(PreviewRect, FListView.BoundsRect)) then
FListView.BoundsRect := PreviewRect;
LabelRect := PreviewRect;
Dec(LabelRect.Top, 24);
LabelRect.Bottom := LabelRect.Top + 16;
FTopLabel.BoundsRect := LabelRect;
LabelRect := PreviewRect;
LabelRect.Top := PreviewRect.Bottom + 9;
LabelRect.Bottom := LabelRect.Top + 16;
FBottomLabel.BoundsRect := LabelRect;
end;
end;
end;
procedure TOpenPictDialog.DoSelectionChange;
var
FullName: string;
function ValidFile(const FileName: string): Boolean;
begin
Result := FileGetAttr(FileName) <> -1;
end;
begin
FullName := FileName;
if FullName <> FSavedFilename then
begin
FSavedFilename := FullName;
end;
inherited DoSelectionChange;
end;
procedure TOpenPictDialog.DoClose;
begin
if Assigned(FDialogMethodInstance) then begin
SetWindowLong(FDialogHandle, GWL_WNDPROC, Integer(FOldDialogWndProc));
FreeObjectInstance(FDialogMethodInstance);
end;
FDialogHandle := 0;
FDialogMethodInstance := NIL;
inherited DoClose;
{ Hide any hint windows left behind }
Application.HideHint;
end;
procedure TOpenPictDialog.DoShow;
var
PreviewRect, StaticRect, OldDialogRect: TRect;
DialogWidth, DialogHeight, NewLeft, NewTop: integer;
const
SizeIncrease = 25;
begin
FDialogHandle := GetParent(Handle);
GetWindowRect(FDialogHandle, OldDialogRect);
DialogWidth := OldDialogRect.Right - OldDialogRect.Left + SizeIncrease;
DialogHeight := OldDialogRect.Bottom - OldDialogRect.Top;
NewLeft := (Screen.Width - DialogWidth) div 2;
NewTop := (Screen.Height - DialogHeight) div 2;
GetWindowRect(Handle, PreviewRect);
MoveWindow(FDialogHandle, NewLeft, NewTop, DialogWidth, DialogHeight, true);
MoveWindow(Handle, 0, 0, PreviewRect.Right - PreviewRect.Left + SizeIncrease, PreviewRect.Bottom - PreviewRect.Top, false);
StaticRect := GetStaticRect;
GetClientRect(Handle, PreviewRect);
PreviewRect.Left := StaticRect.Left + (StaticRect.Right - StaticRect.Left);
Inc(PreviewRect.Top, 4);
Dec(PreviewRect.Right, 8);
Dec(PreviewRect.Bottom, 20);
FListView.BoundsRect := PreviewRect;
FDialogMethodInstance := MakeObjectInstance(DialogWndProc);
FOldDialogWndProc := Pointer(SetWindowLong(FDialogHandle, GWL_WNDPROC, Integer(FDialogMethodInstance)));
FSavedFilename := '';
FListView.ParentWindow := Handle;
FTopLabel.ParentWindow := Handle;
FBottomLabel.ParentWindow := Handle;
inherited DoShow;
end;
[UIPermission(SecurityAction.LinkDemand, Window=UIPermissionWindow.SafeSubWindows)]
function TOpenPictDialog.Execute(ParentWnd: HWND): Boolean;
begin
if NewStyleControls and not (ofOldStyleDialog in Options) and not
((Win32MajorVersion >= 6) and UseLatestCommonDialogs) then
Template := 'DLGTEMPLATE'
else
{$IF DEFINED(CLR)}
Template := '';
{$ELSE}
Template := nil;
{$IFEND}
Result := inherited Execute(ParentWnd);
end;
function TOpenPictDialog.TaskModalDialog(DialogFunc: Pointer; var DialogData): Bool;
begin
// This makes sense ONLY if you are compiling with a run-time packages
// Thanks to Peter Below (www.delphifaq.com)
TOpenfilename(Dialogdata).hInstance := FindClassHInstance(Classtype);
Result := inherited TaskModalDialog(DialogFunc, DialogData);
end;
function TOpenPictDialog.IsFilterStored: Boolean;
begin
Result := not (Filter = GraphicFilter(TGraphic));
end;
procedure Register;
begin
RegisterComponents('Dialogs', [TOpenPictDialog]);
end;
end.
When you copied the code from ExtDlgs.pas to begin writing yours, you didn't copy enough. In particular, you didn't copy the $R directive that links the associated ExtDlgs.rc file, which contains the dialog resource describing the additional layout of the custom dialog box.
Your code tells the API to use a dialog resource named DLGTEMPLATE, but you haven't included that resource in your program. That explains why the error code you get is about a failure to find a resource. Using the ExtDlgs unit has the side effect of linking that unit's associated resources.
Go copy the dialog template from ExtDlgs.rc into your own RC file and link it as ExtDlgs.pas does. Use a different name for the resource, though, to avoid a name clash with the existing DLGTEMPLATE resource. Adjust your code accordingly.

Delphi - ValueListEditor not adding new row

I have a procedure which needs to read data from an ini file with the following format:
'Prices', [integer], [data to be read]
The data read consists of two pieces of information split by a '/' symbol. The data is split successfully when I call my procedure below.
I have a TValueListEditor (called ledtPrices) placed on the form and would like to add the values from the ini file to the List Editor. If I call ledtPrices.InsertRow via a button click, the values I enter into to add to the row are added and the list editor is refreshed.
However, when I call the same function from my RefreshPList procedure, the values are not added as new rows (the list editor is blank). I have tested my code with ShowMessage dialogues to ensure each part of the procedure is functioning when it should. My code is as follows:
procedure RefreshPList;
var
l: TValueListEditor;
xFile: TINIFile;
temprow, tl, tp: string;
tempr: TStringList;
i: integer;
begin
i := 0;
l := frmSettings.ledtPrices;
try
tempr := TStringList.Create;
tempr.StrictDelimiter := True;
tempr.Delimiter := '/';
xFile := TIniFIle.Create('C:\MData.ini');
try
temprow := xFile.ReadString('Prices', '0', 'xx');
if temprow = 'xx' then
ShowMessage('no prices saved')
else
begin
repeat
temprow := xFile.ReadString('Prices', IntToStr(i), 'xx');
if temprow <> 'xx' then
begin
tempr.DelimitedText := temprow;
tl := tempr[0];
tp := tempr[1];
l.InsertRow(tl,tp,true);
//ShowMessage(tl);
Inc(i);
end
else
ShowMessage('End of list');
until (temprow = 'xx');
//l.Refresh;
end;
finally
xFile.Free;
end;
LastLine := i;
finally
tempr.Free;
end;
end;
LastLine is a global integer value to be used later. I'm trying to add, remove and edit data within the list editor, without editing the cells directly. The procedure to add new data to the ini file has been written and runs successfully.
UPDATE
I've come to realise that any procedure that I create which tries to edit a components values does not edit the components values. Am I missing something simple here?
For example, I created a memo on the form and created a procedure which adds the contents of an array to the memo.lines. This procedure did not execute when called from a buttonclick. However, if I copy the contents of the procedure directly into the buttonclick and execute it, it works.
The procedures are called from buttonclick commands. The form is created from a mainform. The components all sit within a pagecontrol tabsheet.
A quick test application (XE5, VCL Forms) cannot reproduce the problem.
I start with a new blank application, drop a TValueListEditor and a TButton on the form, and use the Object Inspector to add two key/value combinations:
Key Value
--- -----
A Aaaaaaa
C Ccccccc
In the TButton.OnClick event, I use the following code:
procedure TForm1.Button1Click(Sender: TObject);
var
NewKey, NewValue: string;
begin
NewKey := 'B';
NewValue := 'Bbbbbbb';
ValueListEditor1.InsertRow(NewKey, NewValue, True);
end;
I run the application:
I click Button1, and the code successfully adds the new item at the end (bottom) of the TValueListEditor.
I change the last parameter to InsertRow to False, and it inserts it at the start (top) of the TValueListEditor.
This indicates that either you're not getting the values you expect from your ini file, or the code that inserts the new row isn't executing.
Here's the full code of the test app I created:
Unit1.dfm
object Form4: TForm1
Left = 0
Top = 0
Caption = 'Form4'
ClientHeight = 178
ClientWidth = 447
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object ValueListEditor1: TValueListEditor
Left = 40
Top = 16
Width = 306
Height = 137
Strings.Strings = (
'A=Aaaaaaa'
'C=Ccccccc')
TabOrder = 0
end
object Button1: TButton
Left = 352
Top = 16
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 1
OnClick = Button1Click
end
end
Unit1.pas
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Grids, Vcl.ValEdit;
type
TForm1 = class(TForm)
ValueListEditor1: TValueListEditor;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
NewKey, NewValue: string;
begin
NewKey := 'B';
NewValue := 'Bbbbbbb';
ValueListEditor1.InsertRow(NewKey, NewValue, True);
end;
end.

Inno Setup/Pascal Scripting - Casting Returning Nil

I'm trying to write some Pascal script for a installer I'm making with Inno Setup Compiler 5.5.1. I'm currently trying to add a custom wizard page that executes a command, taking user input from text fields (TEdit components). I defined the NextButtonClick function, and it checks that the Page ID is the custom page I defined and attempts to retrieve the user input from the field. When I get it from the components of the Page's Surface property, it gets returned as a TComponent. To get the next I need to cast it to a TEdit, so I tried casting it and it seems to be returning nil. Besides the scripting for Inno I've been doing for the past few days, I don't have much experience with Pascal, so I could possibly be doing something wrong. But I'd appreciate the help!
Here's the chunk of code giving me an issue for reference (with debugging lines left in):
function NextButtonClick(CurPageID: Integer): Boolean;
var
ResultCode: Integer;
CurrPage: TWizardPage;
Server : TComponent;
Server2: TEdit;
SurfacePage : TNewNotebookPage;
ServerStr : String;
begin
if CurPageID = 100 then
begin
CurrPage := PageFromID(100);
SurfacePage := CurrPage.Surface;
Server := SurfacePage.Controls[0];
Server2 := TEdit(Server); // RETURNS NIL HERE
if Server2 = nil then
MsgBox('', mbInformation, MB_OK);
ServerStr := Server2.Text;
MsgBox(ServerStr, mbInformation, MB_OK);
//ShellExec('', 'sqlcmd', '-S ' + ServerStr + ' -Q ":r setMemUsage.sql"', ExpandConstant('{app}') + '\sql', SW_SHOW, ewWaitUntilTerminated, ResultCode);
end;
Result := True;
end;
I can't simulate your problem. I've used this minimalistic code:
[Code]
var
CustomPageID: Integer;
procedure InitializeWizard;
var
EditBox: TEdit;
CustomPage: TWizardPage;
begin
CustomPage := CreateCustomPage(wpWelcome, '', '');
CustomPageID := CustomPage.ID;
EditBox := TEdit.Create(WizardForm);
EditBox.Parent := CustomPage.Surface;
end;
procedure CurPageChanged(CurPageID: Integer);
var
EditBox: TEdit;
Component: TComponent;
CustomPage: TWizardPage;
begin
if (CurPageID = CustomPageID) then
begin
CustomPage := PageFromID(CustomPageID);
Component := CustomPage.Surface.Controls[0];
if (Component is TEdit) then
begin
MsgBox('Controls[0] is assigned and is TEdit', mbInformation, MB_OK);
EditBox := TEdit(Component);
EditBox.Text := 'Hi, I''m just a modified edit text!';
end;
end;
end;