Why doesn't the radio button on custom page checked in Inno Setup? - installation

Why don't rbStandardInstallType and rbCustomInstallType radio buttons get checked even though I set the Checked property of one of those to True? On the other hand, rbDefaultMSSQLInstance and rbNamedMSSQLInstance radio buttons do get checked.
I create radio buttons like this:
function CreateRadioButton(
AParent: TNewNotebookPage; AChecked: Boolean; AWidth, ALeft, ATop, AFontSize: Integer;
AFontStyle: TFontStyles; const ACaption: String): TNewRadioButton;
begin
Result := TNewRadioButton.Create(WizardForm);
with Result do
begin
Parent := AParent;
Checked := AChecked;
Width := AWidth;
Left := ALeft;
Top := ATop;
Font.Size := AFontSize;
Font.Style := AFontStyle;
Caption := ACaption;
end;
end;
I have 2 custom pages where I must show my image on the left and some text and radio buttons on the right (2 radio buttons per page).
So, in my InitializeWizard procedure I've written this:
wpSelectInstallTypePage := CreateCustomPage(wpSelectDir, 'Caption', 'Description');
rbStandardInstallType := CreateRadioButton(WizardForm.InnerPage, True, WizardForm.InnerPage.Width, ScaleX(15), WizardForm.MainPanel.Top + ScaleY(30), 9, [fsBold], 'Standard');
rbCustomInstallType := CreateRadioButton(WizardForm.InnerPage, False, rbStandardInstallType.Width, rbStandardInstallType.Left, rbStandardInstallType.Top + rbStandardInstallType .Height + ScaleY(16), 9, [fsBold], 'Custom');
wpMSSQLInstallTypePage := CreateCustomPage(wpSelectInstallTypePage.ID, 'Caption2', 'Description2');
rbDefaultMSSQLInstance := CreateRadioButton(WizardForm.InnerPage, True, WizardForm.InnerPage.Width, ScaleX(15), WizardForm.MainPanel.Top + ScaleY(30), 9, [fsBold], 'DefaultInstance');
rbNamedMSSQLInstance := CreateRadioButton(WizardForm.InnerPage, False, rbDefaultMSSQLInstance.Width, rbDefaultMSSQLInstance.Left, rbDefaultMSSQLInstance.Top + rbDefaultMSSQLInstance.Height + ScaleY(10), 9, [fsBold], 'NamedInstance');
And finally, here's my CurPageChanged code in order to display all the controls properly:
procedure CurPageChanged(CurPageID: Integer);
begin
case CurPageID of
wpSelectInstallTypePage.ID, wpMSSQLInstallTypePage.ID:
WizardForm.InnerNotebook.Visible := False;
else
WizardForm.InnerNotebook.Visible := True;
end;
rbDefaultMSSQLInstance.Visible := CurPageID = wpMSSQLInstallTypePage.ID;
rbNamedMSSQLInstance.Visible := CurPageID = wpMSSQLInstallTypePage.ID;
rbStandardInstallType.Visible := CurPageID = wpSelectInstallTypePage.ID;
rbCustomInstallType.Visible := CurPageID = wpSelectInstallTypePage.ID;
end

You are adding the radio buttons to a wrong parent control (WizardForm.InnerPage). Not to the custom pages you are creating. And you then workaround that flaw by explicitly hiding/showing the radio buttons in CurPageChanged.
As all four radio buttons have the same parent (WizardForm.InnerPage), only one of them can be checked. So when you check the rbDefaultMSSQLInstance, the rbStandardInstallType is implicitly unchecked.
For the correct code, see:
Inno Setup Placing image/control on custom page
(make sure you remove your redundant CurPageChanged code)
You should also consider using CreateInputOptionPage instead of manually adding the radio buttons to a generic custom page.

Related

How to dislay correct x-axis (bottom axis) label from datasource using Teechart (Delphi)

I would like to ask some help on displaying my datasource’s clientname at the bottom of my stacked bar chart. It seems from all the examples that I researched, the bottom chart axis label is set "automatically" by TeeChart looking at the datasource. However I cant seem to get it to work. Below is a picture of what I am trying to achieve.
Picture of what I am trying to achieve
I have three series' which I use to build the stacked chart. I have included a picture of each datasource I use for each query.
Datasources for three series' queries
From my research it seems I can also use the DBChart1GetAxisLabel() to custom set the labels. But I am struggling to understand how to ensure that the correct custom label name is associated with the correct "clientname" from my queries.
Here is a code sample of how I build the charts:
procedure TfrmSupplierAnalytics.btnOKClick(Sender: TObject);
var
S,NewTypeStr, test, clientSql : string;
var seriasNormalOrders:TBarSeries;
var seriasCreditNoteOrders:TBarSeries;
var seriasPartialOrders:TBarSeries;
N, i : integer;
begin
qCreditNoteOrders.Close;
qNormalOrders.Close;
qPartialOrders.Close;
qGetClientIdFromName.Close;
qClients.Close;
DBChart1.CleanupInstance;
DBChart1.ClearChart;
try
for N := 0 to clbClients.Items.Count-1 do
if clbClients.State[N] = cbChecked then begin
test := string(clbClients.Items[N]);
NewTypeStr := NewTypeStr + '(E.clientid = '+
IntToStr(FindClientID(test)) + ')';
clientSql := clientSql + NewTypeStr;
NewTypeStr := ' or ';
end;
except
on E : Exception do
ShowMessage(E.ClassName+' error raised, with message :
'+E.Message);
end;
OpenQueryCreditNoteOrders(clientSql);
OpenQueryPartialOrders(clientSql);
OpenQueryNormalOrders(clientSql);
seriasNormalOrders :=TBarSeries.Create(self);
DBChart1.AddSeries(seriasNormalOrders);
seriasCreditNoteOrders :=TBarSeries.Create(self);
DBChart1.AddSeries(seriasCreditNoteOrders);
seriasPartialOrders :=TBarSeries.Create(self);
DBChart1.AddSeries(seriasPartialOrders);
seriasNormalOrders.MultiBar := mbStacked;
seriasCreditNoteOrders.MultiBar := mbStacked;
seriasPartialOrders.MultiBar := mbStacked;
seriasNormalOrders.Marks.Visible := true;
seriasNormalOrders.MarksLocation:= mlCenter;
seriasNormalOrders.MarksOnBar := True;
seriasNormalOrders.YValues.ValueSource := 'NormalOrders';
seriasNormalOrders.DataSource := qNormalOrders;
seriasNormalOrders.Title := 'Correct Orders';
seriasNormalOrders.Marks.Visible := True;
seriasNormalOrders.Marks.AutoPosition := true;
seriasCreditNoteOrders.YValues.ValueSource := 'CreditNoteOrders';
seriasCreditNoteOrders.DataSource := qCreditNoteOrders;
seriasCreditNoteOrders.Title := 'Credit Note Orders';
seriasPartialOrders.YValues.ValueSource := 'PartialOrders';
seriasPartialOrders.DataSource := qPartialOrders;
seriasPartialOrders.Title := 'Short Orders';
seriasNormalOrders.CheckDataSource;
seriasCreditNoteOrders.CheckDataSource;
seriasPartialOrders.CheckDataSource;
end;
So, just to sum up, is there some setting in my code which I am missing that would show the "clientname" below each stacked bar, or must I use custom labels?
If I must use custom labels, I would appreciate some direction on how to ensure that I replace the correct "clientname" from the datasource to the correct ValueIndex in the DBChart1GetAxisLabel?
Thanks in advance.
I managed to get an answer.
You could set the XLabelsSource to show the text from the DataSource and then set the series Marks.Style to smsValue to force it showing values instead of showing the labels. Ie:
<pre>
procedure TForm1.FormCreate(Sender: TObject);
var ADOQuery1: TADOQuery;
i: Integer;
begin
ADOQuery1:=TADOQuery.Create(Self);
with ADOQuery1 do
begin
ConnectionString:='Provider=MSDASQL.1;Persist Security Info=False;Data
Source=TeeChart Pro Database';
SQL.Add('SELECT SALARY, LASTNAME from Employee WHERE LASTNAME='#39'Smith'#39);
end;
for i:=0 to 1 do
with DBChart1.AddSeries(TBarSeries) as TBarSeries do
begin
XLabelsSource:='LASTNAME';
DataSource:=ADOQuery1;
MultiBar:=mbStacked;
YValues.ValueSource:='SALARY';
Marks.Style:=smsValue;
end;
ADOQuery1.Open;
end;
</pre>
I tested it in my project and it works.

Custom tSpeedButton painting

I have two TSpeedButton buttons on a form. When one button is enabled, the other is disabled and vice versa. I want to paint the buttons with custom colors to reflect whether they are enabled or disabled.
I coded a procedure named SetButtonsColors. This procedure sets (one button at a time), the variables ButtonFillColor and ButtonStrokeColor with the custom colors, accordingly with the button state, and immediately commands the repainting of the button.
On ButtonPaint handler I set the Canvas.Fill.Color and Canvas.Stroke.Color with ButtonFillColor and ButtonStrokeColor respectively and do the filling and drawing of the aRect.
For my disappointment, the buttons are always painted with the colors set for the last button. This happens, I presume, because Windows paints the buttons asynchronous, and hence, uses the last settings for Canvas.Fill.Color and Canvas.Stroke.Color.
If this is true, how can I force Windows to paint the button immediately after it's repainting is commanded?
Follows the code for SetButtonsColors and ButtonPaint:
procedure tForm1.SetButtonsColors;
begin
if Button1.Enabled then begin
ButtonFillColor := tAlphaColorRec.White;
ButtonStrokeColor := tAlphaColorRec.Black;
Button1.Repaint;
ButtonFillColor := tAlphaColorRec.Black;
ButtonStrokeColor := tAlphaColorRec.White;
Button1.Repaint;
end;
else begin
ButtonFillColor := tAlphaColorRec.Black;
ButtonStrokeColor := tAlphaColorRec.White;
Button1.Repaint;
ButtonFillColor := tAlphaColorRec.White;
ButtonStrokeColor := tAlphaColorRec.Black;
Button2.Repaint;
end;
end;
procedure tForm1.ButtonPaint (Sender: tObject; Canvas: tCanvas; const aRect: tRectF);
begin
Canvas.BeginScene;
Canvas.Fill .Color := lvButtonFillColor;
Canvas.Stroke.Color := lvButtonStrokeColor;
Canvas.FillRect (aRect, 0, 0, [] , 1, CornerTypeBevel);
Canvas.DrawRect (aRect, 0, 0, AllCorners, 1, CornerTypeBevel);
Canvas.EndScene;
end;
Thanks.

If statement inside repeat until loop

I'm creating a toggle button using the SwinGame library. Right now I'm struggling with actually making it toggle. That bit looks like this:
var
clr: Color;
clicked: Boolean;
boolcheck: String;
begin
OpenGraphicsWindow('Toggle button test', windowsWidth, windowsHeight);
clr := ColorWhite;
clicked := true;
boolcheck := 'true';
repeat
ClearScreen(clr);
ProcessEvents();
//Play button and Pause button
if (ButtonClicked(buttonX-buttonRadius, buttonY-buttonRadius, buttonRadius*2, buttonRadius*2) = true) and (clicked = true) then
begin
clr := ColorRed;
clicked := false;
boolcheck := 'false';
DrawAButton();
end
else if (ButtonClicked(buttonX-buttonRadius, buttonY-buttonRadius, buttonRadius*2, buttonRadius*2) = true) and (clicked = false) then
begin
clr := ColorBlue;
clicked := true;
boolcheck := 'true';
DrawADifferentButton();
end;
DrawText(echo, ColorBlack, 'arial.ttf', 14, 55, 55);
RefreshScreen();
until WindowCloseRequested();
end;
Basically I intended to make it so if the user clicks on this area of the window via ButtonClicked() (a SwinGame function), and the clicked variable is false, then the background color will be red, if not then blue. But for some reason I could only change it to red, blue did not appear at all. I did some troubleshooting by creating a boolcheck variable and I saw the variable was constantly being put at true, I did see it change to false for a fraction of a second then back to true....But I did not put the clicked variable initial definition inside the loop, so why isn't it staying false?
EDIT: Here's the definition to the ButtonClicked function
function ButtonClicked(posX, posY: Single; w, h: Integer): Boolean;
var
x, y: Single;
begin
x := MouseX();
y := MouseY();
result := false;
if MouseClicked(LeftButton) then
begin
if (x >= posX) and (x <= w + posX) and (y >= posY) and (y <= h + posY) then
begin
result := true;
end;
end;
end;
Ok, thanks to #lurker 's suggestion, I've solved it. After spending some time thinking about #lurker 's suggestion, I realized that once the procedure gets reset, it'll start off with clicked being at 0 again. So what I had to do, was making the the ButtonClicked check a function that returns 1 or 0, or true or false into clicked in Main(). That way clicked will always be updated, and the procedure won't be reset with clicked being at 0 all the time.
function Toggle(clicked): Integer;
if ButtonClicked(buttonX-buttonRadius, buttonY-buttonRadius, buttonRadius*2, buttonRadius*2) then
if (clicked := true) then
begin
clr := ColorRed;
result := false;
DrawAButton();
end
else
begin
clr := ColorBlue;
result := true;
DrawADifferentButton();
end;
then in `Main()` I would call it as follow:
//Stuffs
begin
clicked := true;
repeat
clicked := Toggle(clicked);
//Other stuffs

How to jump to page on on button click?

I need a simple thing: have advance and normal installation buttons. For normal case it is all simple - I used default next button with some logic on NextButtonClick to set a condition variable and skeep some pages using ShouldSkipPage . Yet for advanced setup I created a new button and all I need it to do on click is to open next installer page:
procedure CurPageChanged(CurPageID : Integer);
begin
if CurPageID = wpWelcome then begin
AdvancedButton := TButton.Create(WizardForm);
AdvancedButton.Caption := 'Advanced Install';
AdvancedButton.Left := WizardForm.InfoAfterPage.Left + 10;
AdvancedButton.Top := WizardForm.InfoAfterPage.Height + 88;
AdvancedButton.Parent := WizardForm.NextButton.Parent;
# AdvancedButton.OnClick := What shall I call to open say next page (or some page by given PageID value)
end
else begin
AdvancedButton.Visible := False;
end;
end;
So What shall I call to open say next page (or some page by given PageID value) on my button click (could not find any NextPage or some SetPage function in Inno API)?
There is no such thing as "Direct jump to page" in Inno Setup.
All you need is to quietly skip certain pages in 'Advanced mode'.
Simply do the same as in regular installer. Set one variable for holding 'Advanced mode'. After clicking the Advance button:
[Code]
var
IsAdvanced: Boolean;
procedure AdvancedButtonClick(Sender: TObject);
begin
IsAdvanced := True;
WizardForm.NextButton.OnClick(nil);
end;
procedure InitializeWizard;
var
AdvancedButton: TNewButton;
begin
// not necessary; just for sure
IsAdvanced := False;
// create the button
AdvancedButton := TNewButton.Create(WizardForm);
AdvancedButton.Caption := 'Advanced Install';
AdvancedButton.Left := WizardForm.InfoAfterPage.Left + 10;
AdvancedButton.Top := WizardForm.InfoAfterPage.Height + 88;
AdvancedButton.Parent := WizardForm.NextButton.Parent;
AdvancedButton.OnClick := #AdvancedButtonClick;
end;
function ShouldSkipPage(PageID: Integer): Boolean;
begin
// the <page where you want to end up> fill with the wizard page constant
// of the page where you want to end up, e.g. wpReady
Result := IsAdvanced and (PageID <> <page where you want to end up>);
end;
With this logic you can simulate quiet 'jump' to certain page.

How to get images to show up on TExtButton in ExtPascal?

I've been trying for hours in Lazarus following from the sample code in the
AdvancedTabs unit, to make am image appear on a button.
The sample code has this:
constructor TAdvancedTabs.Create;
var
I : integer;
begin
inherited;
with SelfSession do begin
SetCodePress;
SetStyle('.new-tab{background-image:url(' + ExtPath + '/examples/feed-viewer/images/new_tab.gif) !important}');
SetStyle('.tabs{background:url(' + ExtPath + '/examples/desktop/images/tabs.gif)}');
end;
with TExtButton.Create do begin
RenderTo := 'body';
Text := 'Add Tab using AJAX!';
IconCls := 'new-tab';
Handler := Ajax(AddTab);
OnClick := HandleExtButtonClick; // Delphi style event handler
end;
...
I have this:
extPath := (CurrentFCGIThread as TExtThread).ExtPath;
(CurrentFCGIThread as TExtThread).SetStyle('.backbtn{background-image:url(' + ExtPath + '/basxv2/back.png) !important}');
btnClose := TV2ExtButton.Create;
with btnClose.AddTo(Items) do
begin
Id := 'frmManualOrder_btnClose';
X := MarginLeft;
Height := ButtonHeight;
Y := ScreenHeight-12*MarginLeft;
Width := ButtonWidth-10;
RenderTo := 'body';
IconCls := 'backbtn';
...
I have tried a number of different things, converting the image to a
gif, for example, and in most cases the button is either blank (if I
don't set the Text property) or shows the text nudged to the right a
few pixels as if making room for an invisible image. A few times the image appears with the top and bottom clipped.
Can anyone see what I am doing wrong?
TIA
Mark

Resources