Add a picture button and a label on welcome page in Inno Setup [duplicate] - inno-setup

This question already has an answer here:
How can I add a image banner on the bottom left of the wizard window?
(1 answer)
Closed 11 months ago.
I would like to understand how can I add a button on the welcome page, that once clicked it will open a specific website on the default web-browser.
I just would like to display a kind of picture control that can be pressed to perform an action (in this case, open the software's author website on the web-browser). I can store the image file in the 'embedded' or '{tmp}' directory. If the button can have PNG or ICO transparency it would be better for me, but its not a problem at all.
I would like the picture button to have a square form and to be located at the bottom-left corner like the orange square in this image, covering almost all that area with some width and height pixel margin:
I can manually resize the image file before compiling the setup, to fit the control's width/height, but I'm not sure if the control's size will have the same fixed size on all systems. Anyways I imagine that the control will have its built-in logic to resize at runtime the image to fit its control's size, or not?.
Additional to this, and if someone can help me, I also would like to understand how to add a custom text label and locate it where it says: "Installer made by {name}" (in that exact corner, that is at the right of the logo image panel and the bottom of the welcome page text box)
I'm asking for a generous code sample or instructions to guide me through the process to do this.
UPDATE:
Thanks to this little code example from the OP, and this documentation with the name of properties of TWizardForm class, and this tip I think that I managed to figure out how to do properly the label part.
[Code]
procedure InitializeWizard();
var
InstallerAuthorLabel: TNewStaticText;
begin
InstallerAuthorLabel := TNewStaticText.Create(WizardForm);
InstallerAuthorLabel.Caption := 'Installer by ElektroStudios';
InstallerAuthorLabel.Parent := WizardForm.WelcomePage;
InstallerAuthorLabel.Left := (WizardForm.WizardBitmapImage.Left + WizardForm.WizardBitmapImage.Width) + ScaleX(8);
InstallerAuthorLabel.Top := (WizardForm.WizardBitmapImage.Top + WizardForm.WizardBitmapImage.Height) - ScaleY(20);
end;
It looks like this:
But I'm not sure about how to add a "picture button" on that same page and how to calculate its location because it seems that if I put a control under the WizardBitmapImage bottom height it gets hidden...

Not sure if this code below is done in the correct way, but this is what I was able to do by myself after multiple researches and headaches since I'm a newbie on pascal scripting and of course I don't know almost any member of the Inno Setup classes references:
[Code]
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
// Opens the specified url in the default web-browser. //
// https://stackoverflow.com/a/38934870/1248295 //
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
procedure OpenWebBrowser(Url: string);
var
ErrorCode: Integer;
begin
ShellExec('open', Url, '', '', SW_SHOWNORMAL, ewNoWait, ErrorCode);
end;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
// Occurs when the AuthorWebsiteLabel and AuthorWebsiteBitmap control are clicked. //
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
procedure AuthorWebsiteControlClick(Sender: TObject);
begin
OpenWebBrowser('{#AuthorWebsite}');
end;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
// Use this event function to make changes to the wizard or wizard pages at startup. //
// At the time this event is triggered, the wizard form does not yet exist. //
// https://jrsoftware.org/ishelp/index.php?topic=scriptevents //
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
<event('InitializeWizard')>
procedure InitializeWizard1();
var
InstallerAuthorLabel: TNewStaticText;
AuthorWebsiteLabel : TNewStaticText;
AuthorWebsiteBitmap : TBitmapImage;
begin
// Set AuthorWebsiteBitmap control properties...
AuthorWebsiteBitmap := TBitmapImage.Create(WizardForm);
AuthorWebsiteBitmap.Parent := WizardForm.WelcomePage;
AuthorWebsiteBitmap.AutoSize := True;
AuthorWebsiteBitmap.Left := (WizardForm.WizardBitmapImage.Left + WizardForm.WizardBitmapImage.Width) + ScaleX(10);
AuthorWebsiteBitmap.Top := (WizardForm.WelcomeLabel2.Top + WizardForm.WelcomeLabel2.Height) - (AuthorWebsiteBitmap.Height div 2) - ScaleX(16);
AuthorWebsiteBitmap.Cursor := crHand
AuthorWebsiteBitmap.OnClick := #AuthorWebsiteControlClick;
ExtractTemporaryFile('AuthorWebsite.bmp');
AuthorWebsiteBitmap.Bitmap.LoadFromFile(ExpandConstant('{tmp}\AuthorWebsite.bmp'));
// Resize WelcomeLabel2 height to be able see AuthorWebsiteBitmap control.
WizardForm.WelcomeLabel2.Height := WizardForm.WelcomeLabel2.Height - (AuthorWebsiteBitmap.Height + ScaleY(8));
// This will not work...
// AuthorWebsiteBitmap.BringToFront();
// Set AuthorWebsiteLabel control properties...
AuthorWebsiteLabel := TNewStaticText.Create(WizardForm);
AuthorWebsiteLabel.Caption := 'Navigate to author''s website...';
AuthorWebsiteLabel.Parent := WizardForm.WelcomePage;
AuthorWebsiteLabel.Left := AuthorWebsiteBitmap.Left;
AuthorWebsiteLabel.Top := AuthorWebsiteBitmap.Top - ScaleY(18);
AuthorWebsiteLabel.Cursor := crHand;
AuthorWebsiteLabel.OnClick := #AuthorWebsiteControlClick;
// Set InstallerAuthorLabel control properties...
InstallerAuthorLabel := TNewStaticText.Create(WizardForm);
InstallerAuthorLabel.Caption := 'Installer created by ElektroStudios';
InstallerAuthorLabel.Parent := WizardForm;
InstallerAuthorLabel.Left := ScaleX(2);
InstallerAuthorLabel.Top := WizardForm.NextButton.Top + WizardForm.NextButton.Height div 2 + ScaleY(10) - ScaleY(2);
end;

Related

Remove image from the last Finished page of Inno Setup

How to customize last page (wpFinished) to only have a message, but keep the bottom buttons, like this:
I don't want the image on the left that is there by default.
I was trying to create new page, but don't know how to hide the default finished page or add bottom buttons (Back, Finished, Cancel) on new page.
Hide the WizardBitmapImage2 control and extend remaining controls accordingly.
Something like this:
[Code]
procedure ExtendFinishedPageControl(Control: TControl);
begin
Control.Left := Control.Left - WizardForm.WizardBitmapImage2.Width;
Control.Width := Control.Width + WizardForm.WizardBitmapImage2.Width;
end;
procedure InitializeWizard();
begin
WizardForm.WizardBitmapImage2.Visible := False;
ExtendFinishedPageControl(WizardForm.RunList);
ExtendFinishedPageControl(WizardForm.NoRadio);
ExtendFinishedPageControl(WizardForm.YesRadio);
ExtendFinishedPageControl(WizardForm.FinishedLabel);
ExtendFinishedPageControl(WizardForm.FinishedHeadingLabel);
end;

Set image as per the resolution in Inno Setup [duplicate]

Bitmap for Inno Setup WizardImageFile (and WizardSmallImageFile) looks terrible because when Windows 7 has the large system fonts enabled, the Wizard is bigger than usual, but the images are scaled terrible wrong.
Is there a fix?
There is no similar issue if I add own picture somewhere like this:
BitmapImage1.AutoSize := True;
BitmapImage1.Align := alClient;
BitmapImage1.Left := 0;
BitmapImage1.Top := 0;
BitmapImage1.stretch := True;
BitmapImage1.Parent := Splash;
These are bitmap images, they naturally scale badly. You are just lucky that your own images do not look that bad when scaled.
You have to prepare your own set of images for common scaling factors.
Common scaling factors used nowadays are 100%, 125%, 150% and 200%. So you should have four sizes for the images, like:
WizardImage 100.bmp
WizardImage 125.bmp
WizardImage 150.bmp
WizardImage 200.bmp
WizardSmallImage 100.bmp
WizardSmallImage 125.bmp
WizardSmallImage 150.bmp
WizardSmallImage 200.bmp
Inno Setup can automatically select the best version of the image since 5.6.
Just list your versions of the images in the WizardImageFile and WizardSmallImageFile. You can use wildcards:
[Setup]
WizardImageFile=WizardImage *.bmp
WizardImageFile=WizardSmallImage *.bmp
On older versions of Inno Setup (or if your need to customize the selection algorithm or when you have additional custom images in the wizard), you would have to select the images programatically.
The following example does more or less the same what Inno Setup 5.6:
[Setup]
; Use 100% images by default
WizardImageFile=WizardImage 100.bmp
WizardSmallImageFile=WizardSmallImage 100.bmp
[Files]
; Embed all other sizes to the installer
Source: "WizardImage *.bmp"; Excludes: "* 100.bmp"; Flags: dontcopy
Source: "WizardSmallImage *.bmp"; Excludes: "* 100.bmp"; Flags: dontcopy
[Code]
function GetScalingFactor: Integer;
begin
if WizardForm.Font.PixelsPerInch >= 192 then Result := 200
else
if WizardForm.Font.PixelsPerInch >= 144 then Result := 150
else
if WizardForm.Font.PixelsPerInch >= 120 then Result := 125
else Result := 100;
end;
procedure LoadEmbededScaledImage(Image: TBitmapImage; NameBase: string);
var
Name: String;
FileName: String;
begin
Name := Format('%s %d.bmp', [NameBase, GetScalingFactor]);
ExtractTemporaryFile(Name);
FileName := ExpandConstant('{tmp}\' + Name);
Image.Bitmap.LoadFromFile(FileName);
DeleteFile(FileName);
end;
procedure InitializeWizard;
begin
{ If using larger scaling, load the correct size of images }
if GetScalingFactor > 100 then
begin
LoadEmbededScaledImage(WizardForm.WizardBitmapImage, 'WizardImage');
LoadEmbededScaledImage(WizardForm.WizardBitmapImage2, 'WizardImage');
LoadEmbededScaledImage(WizardForm.WizardSmallBitmapImage, 'WizardSmallImage');
end;
end;
You might want to do the same for the SelectDirBitmapImage, the SelectGroupBitmapImage and the PreparingErrorBitmapImage.
See also:
How to detect and "fix" DPI settings with Inno Setup?
Inno Setup Placing image/control on custom page

Any way to inspect all the <a> information of a button on website after selenium has selected that element?

Is it possible to look into the details of a button element I identify with selenium?
I'm using selenium to navigate JS heavy web pages. I want to download some files from these webpages but first I must request the files be made available (which then join a que of requests in a table on the webpage) and after some time (and a webpage refresh) a download button becomes available on my particular row on the table. I see that all the download buttons (NOT LINK TEXT) have a unique and unpredictable reference Id in their href, but also include in them a unique identifier to the request (e.g. in this case '2020Apr8 2020Apr9'):
<a class="a-button-text" href="/payments/reports/download?_encoding=UTF8&contentType=text%2Fcsv&fileName=2020Apr8-2020Apr9CustomTransaction.csv&referenceId=80808018362" role="button">Download</a>
<a class="a-button-text" href="/payments/reports/download?_encoding=UTF8&contentType=text%2Fcsv&fileName=2019Mar23-2020Mar1CustomTransaction.csv&referenceId=80631018357" role="button">Download</a>
Besides the inclusion of '2020Apr8 2020Apr9' in the href I don't think there is an easy, predictable, and unique way of identifying this download button as the one that pertains to the information I care to download (or .click()).
here is the code I am using to look at the button elements with selenium:
from selenium import webdriver
browser = webdriver.Firefox() # spin up firefox
browser.get('Website address') # navigate to relevant page
get_button_elements = browser.find_elements_by_css_selector('a.a-button-text')
If I look at the get_button_elements object:
for button in get_button_object:
print(button)
output looks like this
<selenium.webdriver.firefox.webelement.FirefoxWebElement (session="a0c542b6-7c21-4851-bc50-39a5a7362e9a", element="9cb24e04-cdbf-49f5-99a2-fa91df862814")>
<selenium.webdriver.firefox.webelement.FirefoxWebElement (session="a0c542b6-7c21-4851-bc50-39a5a7362e9a", element="28de61df-9bdf-4c9d-aae3-d1658bf0abfa")>
I believe these are the three download buttons I currently see on the page. There are numerous other 'reqeusts' on the page without download buttons, but 3 download buttons are present.
Is there a way for me to see what the href is of these buttons?
my plan would is to:
refresh the page
create selenium object containing all the
buttons
see if any of the buttons contain the unique identifier
(e.g. '2020Apr8 2020Apr9')
if yes, then click.
EDIT
get_div = browser.find_element_by_xpath("//a[#class='a-button-text'][contains(#href, '2020Apr8 2020Apr9')]")
for element in get_div:
print(element)
Traceback:
Traceback (most recent call last):
File "C:/Users/mbsta/PycharmProjects/untitled2/Amazon_Seller_Central.py", line 249, in <module>
download_custom_transcation_reports()
File "C:/Users/mbsta/PycharmProjects/untitled2/Amazon_Seller_Central.py", line 179, in download_custom_transcation_reports
get_div = browser.find_element_by_xpath("//a[#class='a-button-text'][contains(#href, '2020Apr8 2020Apr9')]")
File "C:\Users\mbsta\Anaconda3\envs\untitled2\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 394, in find_element_by_xpath
return self.find_element(by=By.XPATH, value=xpath)
File "C:\Users\mbsta\Anaconda3\envs\untitled2\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 978, in find_element
'value': value})['value']
File "C:\Users\mbsta\Anaconda3\envs\untitled2\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 321, in execute
self.error_handler.check_response(response)
File "C:\Users\mbsta\Anaconda3\envs\untitled2\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: //a[#class='a-button-text'][contains(#href, '2020Apr8 2020Apr9')]
EDIT 2
Some have asked for more info on the page. This is a amazon seller central page. I'd rather avoid using anything with broad paths to find the buttons since amazon changes things periodically and I'd like it to not break this whole thing.
If I select the 'copy CSS path' to where a button would be, this is what I get:
html.asp - ws.a - ember.a - transition.a - transform.a - opacity.a - border - image.a - border - radius.a - box - shadow.a - text - stroke.a - text - shadow.a - touch - scrolling.a - transform3d.a - gradients.a - local - storage.a - textarea - placeholder.a - input - placeholder.a - autofocus.a - webworker.a - history.a - geolocation.a - drag - drop.a - svg.a - canvas.a - video.a - audio.a - js.asp - js.asp - audio.asp - video.asp - canvas.asp - drag - drop.asp - geolocation.asp - history.asp - autofocus.asp - input - placeholder.asp - textarea - placeholder.asp - local - storage.asp - gradients.asp - transform3d.asp - touch - scrolling.asp - text - shadow.asp - text - stroke.asp - box - shadow.asp - border - radius.asp - border - image.asp - opacity.asp - transform.asp - transition.a - ws
body.a - aui_72554 - c.a - aui_dropdown_187959 - c.a - aui_pci_risk_banner_210084 - c.a - aui_perf_130093 - c.a - aui_preload_261698 - c.a - aui_tnr_v2_180836 - c.a - aui_ux_145937 - c.a - meter - animate
div # a-page div#sc-content-container div.a-row div.a-column.a-span8 div#reportsTable div#daterangereportstable.mt-container.clearfix div.mt-content.clearfix div.mt-table-container.clearfix table.a-bordered.a-horizontal-stripes.mt-table tbody tr#3.mt-row td#3-ddrAction.mt-cell.mt-left span#downloadButton.a-button.a-button-primary.a-button-small span.a-button-inner a.a-button-text
'copy CSS path' for a button not yet loaded:
html.asp - ws.a - ember.a - transition.a - transform.a - opacity.a - border - image.a - border - radius.a - box - shadow.a - text - stroke.a - text - shadow.a - touch - scrolling.a - transform3d.a - gradients.a - local - storage.a - textarea - placeholder.a - input - placeholder.a - autofocus.a - webworker.a - history.a - geolocation.a - drag - drop.a - svg.a - canvas.a - video.a - audio.a - js.asp - js.asp - audio.asp - video.asp - canvas.asp - drag - drop.asp - geolocation.asp - history.asp - autofocus.asp - input - placeholder.asp - textarea - placeholder.asp - local - storage.asp - gradients.asp - transform3d.asp - touch - scrolling.asp - text - shadow.asp - text - stroke.asp - box - shadow.asp - border - radius.asp - border - image.asp - opacity.asp - transform.asp - transition.a - ws
body.a - aui_72554 - c.a - aui_dropdown_187959 - c.a - aui_pci_risk_banner_210084 - c.a - aui_perf_130093 - c.a - aui_preload_261698 - c.a - aui_tnr_v2_180836 - c.a - aui_ux_145937 - c.a - meter - animate
div # a-page div#sc-content-container div.a-row div.a-column.a-span8 div#reportsTable div#daterangereportstable.mt-container.clearfix div.mt-content.clearfix div.mt-table-container.clearfix table.a-bordered.a-horizontal-stripes.mt-table tbody tr#0.mt-row td#0-ddrAction.mt-cell.mt-left div a.drrRefreshTable
Try changing
get_button_elements
to
driver.find_element_by_xpath("//a[#class='a-button-text'][contains(#href, '2020Apr8 2020Apr9')]")
and see if it works.
Edit:
Per your comment - not sure why you're getting the error messages in your question. So just to demonstrate (since I don't have the actual html of the page) - let's say your html is this:
buttons = """
<body>
<div>
<a class="a-button-text"
href="/payments/reports/download?_encoding=UTF8&contentType=text%2Fcsv&fileName=2020Apr8 2020Apr9CustomTransaction.csv&referenceId=80808018362"
role="button">Button I want</a>
</div>
<div>
<a class="a-button-text"
href="/payments/reports/download?_encoding=UTF8&contentType=text%2Fcsv&fileName=2019Mar23-2020Mar1CustomTransaction.csv&referenceId=80631018357"
role="button">Button I don't want</a>
</div>
</body>
"""
And your code is:
from selenium import webdriver
driver = webdriver.Firefox()
driver.get("data:text/html;charset=utf-8,{html_content}".format(html_content=buttons))
Then this xpath expression selects the right button:
driver.find_element_by_xpath("//a[#class='a-button-text'][contains(#href, '2020Apr8 2020Apr9')]").text
Output:
'Button I want'
Can you please check below solution :
WebDriverWait(driver, 30).until(EC.element_to_be_clickable((By.XPATH, "//a[#href='2020Apr8-2020Apr9' and contains(.,'Download')]"))).click()
Note : please add below imports to your solution
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
Note: If you get the timeout exceptions from above xpath as well then please check if there any iframe present on the webpage. If so , then you have to switch to iframe before clicking on above element

Inno Setup - Change size of page name and description labels

I'm using this solution:
Display image in top panel of Inno Setup wizard instead of page title and description
And I want set parameters like this:
WizardForm.WizardSmallBitmapImage.Visible := False;
WizardForm.PageDescriptionLabel.Color := clBlack;
WizardForm.PageNameLabel.Color := clBlack;
WizardForm.PageDescriptionLabel.Font.Color := clWhite;
WizardForm.PageNameLabel.Font.Color := clWhite;
but... i don't know how to make black backgrounds shorter under title and description. As you can see black strips going on to the face. It is possible at all?
I want something like this:
Already i have this:
To change labels width use theirs .Width property.
procedure InitializeWizard();
begin
{ ... }
WizardForm.PageDescriptionLabel.Width :=
WizardForm.PageDescriptionLabel.Width - ScaleX(120);
WizardForm.PageNameLabel.Width :=
WizardForm.PageNameLabel.Width - ScaleX(120);
end;
Or you can make the labels transparent:
Inno Setup - Transparency under text in page name and description labels

How to create two LicenseFile pages in Inno Setup

I'm making an Inno setup for my application. I'm using this command:
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"; LicenseFile: "C:\Users\LocDaiLe\Desktop\license.txt"
to display a license agreement window, but I want two license agreement window right after each others. How can I archieve this - thank you
You have to code the second license page as a custom page.
You can start with the CreateOutputMsgMemoPage function, which creates a page with a memo. Then, you just add radio buttons for accepting the license.
[Files]
; Embed the second license files
; (the part after underscore must match the Name parameter from Languages section)
Source: "license2_english.txt"; Flags: dontcopy
Source: "license2_czech.txt"; Flags: dontcopy
; Other languages
[Code]
var
SecondLicensePage: TOutputMsgMemoWizardPage;
License2AcceptedRadio: TRadioButton;
License2NotAcceptedRadio: TRadioButton;
procedure CheckLicense2Accepted(Sender: TObject);
begin
// Update Next button when user (un)accepts the license
WizardForm.NextButton.Enabled := License2AcceptedRadio.Checked;
end;
function CloneLicenseRadioButton(Source: TRadioButton): TRadioButton;
begin
Result := TRadioButton.Create(WizardForm);
Result.Parent := SecondLicensePage.Surface;
Result.Caption := Source.Caption;
Result.Left := Source.Left;
Result.Top := Source.Top;
Result.Width := Source.Width;
Result.Height := Source.Height;
// Needed for WizardStyle=modern / WizardResizable=yes
Result.Anchors := Source.Anchors;
Result.OnClick := #CheckLicense2Accepted;
end;
procedure InitializeWizard();
var
LicenseFileName: string;
LicenseFilePath: string;
begin
// Create second license page, with the same labels as the original license page
SecondLicensePage :=
CreateOutputMsgMemoPage(
wpLicense, SetupMessage(msgWizardLicense), SetupMessage(msgLicenseLabel),
SetupMessage(msgLicenseLabel3), '');
// Shrink license box to make space for radio buttons
SecondLicensePage.RichEditViewer.Height := WizardForm.LicenseMemo.Height;
// Load license
// Loading ex-post, as Lines.LoadFromFile supports UTF-8,
// contrary to LoadStringFromFile.
LicenseFileName := 'license2_' + ActiveLanguage + '.txt';
ExtractTemporaryFile(LicenseFileName);
LicenseFilePath := ExpandConstant('{tmp}\' + LicenseFileName);
SecondLicensePage.RichEditViewer.Lines.LoadFromFile(LicenseFilePath);
DeleteFile(LicenseFilePath);
// Clone accept/do not accept radio buttons for the second license
License2AcceptedRadio :=
CloneLicenseRadioButton(WizardForm.LicenseAcceptedRadio);
License2NotAcceptedRadio :=
CloneLicenseRadioButton(WizardForm.LicenseNotAcceptedRadio);
// Initially not accepted
License2NotAcceptedRadio.Checked := True;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
// Update Next button when user gets to second license page
if CurPageID = SecondLicensePage.ID then
begin
CheckLicense2Accepted(nil);
end;
end;
For a generalization of the solution that allows adding any number of license pages, see:
Inno Setup - Add 4 license pages
Original (first) license page:
Coded (second) license page:
I also had to display two license files, but I did it by adding these two lines to the setup sectiony:
LicenseFile={#MyFileSource}License.rtf
InfoBeforeFile={#MyFileSource}License2.rtf
Works like a charm for me

Resources