Показать полную графическую версию : Скрипты Inno Setup. Помощь и советы [часть 5]
Gnom_aka_Lexander
28-12-2012, 20:02
те GetIniString(...) = 'yes' значит True »
а еще есть функция GetIniBool, что проще мне кажется. и в код уважаемого El Sanchez совсем несложно ее добавить.
Прототип:
function GetIniBool(const Section, Key: String; const Default: Boolean; const Filename: String): Boolean;
Raf-9600
28-12-2012, 20:16
в Voice=false нет необходимости
Checked[Items.IndexOf('a')] принмает булев значение (True, False), но мы проверяем условие (сравниваем значения)
те GetIniString(...) = 'yes' значит True »
Это не от недопонимания написано, просто такой стиль, если можно так выразиться...
а если там нет 'yes' или стоит что-то другое или пусто то будет False, те айтем не будет отмечен, то бишь галки не будет »
Понял, поспешил с вопросом. Я думал что если не найдёт значение то возмёт его из самого инсталлятора, а не снимет галочку.
Возникла проблема. Почему-то часть параметров работают отлично, но остальные вызывают ошибку "List index out of bounds" при запуске инсталлятора. Собсно вот кусок кода, почему-то строчка c "cm:Game" проходит отлично, а "cm:backup" вызывает ошибку:
procedure InitializeWizard();
var
iFile: TIniFile;
begin
iFile := ParseIniFile(ExpandConstant('{src}\PreSelector.ini'));
with WizardForm.ComponentsList do
begin
Checked[Items.IndexOf(ExpandConstant('{cm:Game}'))] := GetIniValue('Game', 'Backup', '', iFile) = 'true';
Checked[Items.IndexOf(ExpandConstant('{cm:backup}'))] := GetIniValue('Game', 'Type', '', iFile) = 'Full';
end;
end;
Наличие "расшифровки" cm:backup проверил, правильность написания с тем что указано в секции инсталлятора [Components] - тоже, но абсолютно не понимаю, из-за чего может быть ошибка?
Johny777
28-12-2012, 20:44
а еще есть функция GetIniBool, что проще мне кажется. и в код уважаемого El Sanchez совсем несложно ее добавить. »
добавил :). Думаю Raf-9600 так будет проще
function IsKey(const Section, Key: String; Default: boolean; iFile: TIniFile): BOOL;
var
i, j: Integer;
begin
Result := Default;
for i := 0 to GetArrayLength(iFile)-1 do if CompareText(iFile[i].Section, Section) = 0 then
begin
for j := 0 to iFile[i].Entries.Count-1 do if CompareText(iFile[i].Entries.Names[j], Key) = 0 then
begin
Result := iFile[i].Entries.Values[Key] = 'True';
Break;
end;
Break;
end;
end;
Raf-9600, функция function IsKey(const Section, Key: String; iFile: TIniFile): BOOL;
где
первый входной параметр - String - имя секции
второй входной параметр - String - имя ключа
третий входной - возвращаемое по умолчанию булев значение (а то что если секции или ключа нет, а компонент по умолчанию должен быть отмечен или не отмечен)
четвёртый входной параметр - TIniFile
если в таком-то ключе такой-то секции значение 'True', то функция вернёт True, в противном случае False
пример:
procedure InitializeWizard();
var
iFile: TIniFile;
begin
iFile := ParseIniFile(ExpandConstant('{src}\PreSelector.ini'));
with WizardForm.ComponentsList do
begin
Checked[Items.IndexOf(ExpandConstant('{cm:Game}'))] := IsKey('Game', 'Backup', False, iFile);
Checked[Items.IndexOf(ExpandConstant('{cm:backup}'))] := GetIniValue('Game', 'Type', '', iFile) = 'Full';
end;
end;
============================
лучше юзай для своих сообщений вместо функции ExpandConstant('{cm:backup}')) другую - CustomMessage('backup')
она в примерно 2 раза быстрее вернёт строку сообщения для текущего языка
тест:
[Setup]
AppName=My Program
AppVerName=My Program v 1.5
DefaultDirName={pf}\My Program
OutputDir=.
[CustomMessages]
H=fffffffffffffffffffffff
[ code]
function GetTickCount: DWORD; external 'GetTickCount@kernel32.dll stdcall';
procedure InitializeWizard();
var
i: Integer;
dwStartTime: DWORD;
begin
dwStartTime := GetTickCount;
for i := 0 to 100000 do CustomMessage('H');
// for i := 0 to 100000 do ExpandConstant('{cm:H}');
MsgBox(IntToStr(GetTickCount-dwStartTime), mbInformation, MB_OK);
end;
"List index out of bounds" »
а он Enabled? (или нет флага fixed)
===================================
UPD: обновил функцию
Raf-9600
28-12-2012, 22:15
Думаю Raf-9600 так будет проще »
Благодарю. Пока что эту функцию не встраивал, так как все ещё не могу разобраться с ошибкой "List index out of bounds".
Если у тебя есть время, посмотри, пожалуйста, более полный исходник:
[Setup]
AppName=My Application
AppVersion=1.5
DefaultDirName={pf}\My Application
LanguageDetectionMethod=uilanguage
ShowLanguageDialog=auto
[CustomMessages]
ru.TypeOfInstallation=Тип установки:
en.TypeOfInstallation=Type of installation:
ru.Game=Обычный
en.Game=Normal
ru.portable=Портативный
en.portable=Portable
ru.OnlyLocalization=Локализация
en.OnlyLocalization=Localization
ru.backup=Резервная копия
en.backupєckup
ru.FullInstallation=Полная установка
en.FullInstallation=Full installation
[Languages]
Name: "ru"; MessagesFile: "compiler:Languages\Russian.isl"
Name: "en"; MessagesFile: "compiler:Default.isl"
[Components]
Name: "Game"; Description: "{cm:TypeOfInstallation}"; Flags: disablenouninstallwarning;
Name: "Game\Full"; Description: "{cm:Game}"; Flags: exclusive disablenouninstallwarning; Types: full
Name: "Game\Pottable"; Description: "{cm:portable}"; Flags: exclusive disablenouninstallwarning;
Name: "Game\Lokal"; Description: "{cm:OnlyLocalization}"; Flags: collapsed disablenouninstallwarning;
Name: "Game\Lokal\Backup"; Description: "{cm:backup}"; Flags: disablenouninstallwarning;
[Types]
Name: "full"; Description: "{cm:FullInstallation}"; Flags: iscustom
[ Code]
type
TIniFile = array of record
Section: String;
Entries: TStringList;
end;
function ParseIniFile(const Filename: String): TIniFile;
var
iFile: TArrayOfString;
i: Integer;
begin
if not FileExists(Filename) then Exit;
SetArrayLength(Result, 0);
LoadStringsFromFile(Filename, iFile);
for i := 0 to GetArrayLength(iFile)-1 do
begin
//для всех непустых строк, исключая комментарии
if (iFile[i] <> '') and (Copy(iFile[i], 1, 1) <> ';') then
begin
//если строка является секцией...
if (Pos('[', iFile[i]) = 1) and (Pos(']', iFile[i]) = Length(iFile[i])) then
begin
//...пишем в результат имя секции...
SetArrayLength(Result, GetArrayLength(Result)+1);
Result[GetArrayLength(Result)-1].Section := Copy(iFile[i], 2, Length(iFile[i])-2);
end
else
begin
//...иначе пишем пару параметр/значение
if TObject(Result[GetArrayLength(Result)-1].Entries) = nil then
Result[GetArrayLength(Result)-1].Entries := TStringList.Create;
Result[GetArrayLength(Result)-1].Entries.Append(iFile[i]);
end;
end;
end;
end;
//своя функция для чтения значений параметров из секций
function GetIniValue(const Section, Key, Default: String; iFile: TIniFile): String;
var
i, j: Integer;
begin
Result := Default;
for i := 0 to GetArrayLength(iFile)-1 do if CompareText(iFile[i].Section, Section) = 0 then
begin
for j := 0 to iFile[i].Entries.Count-1 do if CompareText(iFile[i].Entries.Names[j], Key) = 0 then
begin
Result := iFile[i].Entries.Values[Key];
Break;
end;
Break;
end;
end;
procedure InitializeWizard();
var
iFile: TIniFile;
begin
iFile := ParseIniFile(ExpandConstant('{src}\PreSelector.ini'));
with WizardForm.ComponentsList do
begin
Checked[Items.IndexOf(CustomMessage('Game'))] := GetIniValue('Game', 'Type', '', iFile) = 'Full';
Checked[Items.IndexOf(CustomMessage('backup'))] := GetIniValue('Game', 'Backup', '', iFile) = 'true';
end;
end;
El Sanchez
28-12-2012, 23:12
Пока что эту функцию не встраивал, так как все ещё не могу разобраться с ошибкой "List index out of bounds" »
Raf-9600, потому что из-за флага collapsed компонента Game\Lokal не отображается дочерний компонент. Нужно для родителя (Game\Lokal) вместо collapsed написать checkablealone, для дочки (Game\Lokal\Backup) добавить dontinheritcheck.
Raf-9600
29-12-2012, 00:46
потому что из-за флага collapsed компонента Game\Lokal не отображается дочерний компонент. »
А есть ли какой-то способ подружить collapsed и загрузку информации о выбранных компонентах из .ini? Просто ведь когда число компонентов переваливает за сотню, то без "сворачивания" ну никак не обойтись =\
Nightwishh
30-12-2012, 00:15
Доброго времени суток, господа. Не подскажите как в ISDone 6.0 в LabelCurrFileName: TLabel; (надпись "Извлекается файл") показывалось только название извлекаемого файла в данный момент и никакого пути перед ним?
Gnom_aka_Lexander
30-12-2012, 11:23
Nightwishh, Ответ - использовать ExtractFileName :
function ProgressCallback(OveralPct,CurrentPct: integer;CurrentFile,TimeStr1,TimeStr2,TimeStr3:PAnsiChar): longword;
begin
.................................................
LabelCurrFileName.Caption:=ExpandConstant('{cm:ExtractedFile} ')+MinimizePathName(ExtractFileName(CurrentFile),...............
...............................................
end;
А есть ли какой-то способ подружить collapsed и загрузку информации о выбранных компонентах из .ini? »
есть. после НГ накидаю, если не забуду, сейчас уже не в состоянии :)
Gnom_aka_Lexander, тогда уж MinimizePathName не нужно.
LabelCurrFileName.Caption:=ExpandConstant('{cm:ExtractedFile} ')+ExtractFileName(CurrentFile);
Gnom_aka_Lexander
30-12-2012, 13:25
тогда уж MinimizePathName не нужно. »
а если имя файла настолько длинное, что не влезет в длинну лейбела?. хотя, может ты и прав :) нужно тогда придумать что-то типа прокрутки непомещающегося текста :)
Raf-9600
30-12-2012, 14:14
после НГ накидаю, если не забуду, сейчас уже не в состоянии »
А я уже нашёл выход. Правда не знаю ли он достаточно производителен, но с флагом collapsed дружит :)
procedure InitializeWizard();
var
iFile: TIniFile;
i: Integer;
begin
iFile := ParseIniFile(ExpandConstant('{src}\PreSelector.ini'));
for i := 0 to WizardForm.ComponentsList.ItemCount - 1 do
begin
case WizardForm.ComponentsList.ItemCaption[i] of
CustomMessage('backup') :
WizardForm.ComponentsList.Checked[i] := GetIniValue('Game', 'Backup', '', iFile) = 'true';
end;
end;
end;
Gnom_aka_Lexander
30-12-2012, 14:21
WizardForm.ComponentsList.Checked[i] »
не рекомендую именно так делать.
WizardForm.ComponentsList.CheckItem(i, coCheck); для выбора компонента
WizardForm.ComponentsList.CheckItem(i, coUncheck); для снятия галки с компонента.
Почему именно так? потому, что при этом выполняется OnClickCheck для ComponentsList, чего не происходит при вашем варианте. и при обновлении, как не расставляй галки, с помощью Checked, при установке это не будет учтено. плюч даля зависимых компонентов при данном способе, достаточно указать только то, что должно быть выбрано, отпадает нужда проверять ошибки в выборе зависимых компонентов, что уже громадный плюс к производительности. ну и фугкцию лучше все-таки булевую использовать, тем более что джонни дал пример.
Raf-9600
30-12-2012, 14:43
и при обновлении, как не расставляй галки, с помощью Checked, при установке это не будет учтено. »
Не понял.
плюч даля зависимых компонентов при данном способе, достаточно указать только то, что должно быть выбрано, отпадает нужда проверять ошибки в выборе зависимых компонентов »
У меня такая проблема вообще не стоит. Мне как рас нужно чтобы к примеру если пользователь выбрал "Локализация" то автоматически выбирался дочерний компонент "Резервная копия".
потому, что при этом выполняется OnClickCheck для ComponentsList, чего не происходит при вашем варианте »
А чем OnClickCheck полезен? (сорри, я нуб)
WizardForm.ComponentsList.CheckItem(i, coCheck); для выбора компонента »
Когда пишу так, то компилятор жалуется на ошибку синтаксиса:
WizardForm.ComponentsList.CheckItem(i, coCheck) := GetIniValue('Game', 'Backup', '', iFile) = 'true';
ну и фугкцию лучше все-таки булевую использовать, тем более что джонни дал пример »
Я знаю и позже её встрою.
Gnom_aka_Lexander
30-12-2012, 14:50
Когда пишу так, то компилятор жалуется на ошибку синтаксиса: »
потому что нужно так:
if GetIniValue('Game', 'Backup', '', iFile) = 'true' then WizardForm.ComponentsList.CheckItem(i, coCheck)
зависимые компоненты, это например, радиобаттоны. при повторной установке будет автоматом выбран предыдущий набор, и вполне вероятен вариант одновременного выбора компонентов взаимоисключающих. чего никогда не будет при предложенном мной варианте, каковой был мною взять из одного из примеров товарища Serega.
Raf-9600
30-12-2012, 15:04
при повторной установке будет автоматом выбран предыдущий набор, и вполне вероятен вариант одновременного выбора компонентов взаимоисключающих. чего никогда не будет при предложенном мной варианте »
Наверно я снова чего-то недопонял. Только что попробовал "свой" вариант, и установил компонент Game\Full, потом сразу запустил инсталлятор повторно и он по умолчанию выбрал Game\Lokal (который прописан в .ini). Ваш код повел себя точно так же. Это конечно недостаток, так как я использую деинсталлятор UninsHs, который добавляет функции изменить набор компонентов и восстановить. Так вот то что при повторном запуске инсталлятора будет не тот набор компонентов что устанавливал пользователь, а тот что прописан в .ini, затруднит использования функции изменения компонентов, а как себя поведет функция "восстановить" я даже не представляю.
Gnom_aka_Lexander
30-12-2012, 15:44
Raf-9600, я просто говорю, как будет более правильно чекать компоненты. как делать на самом деле - дело исключительно ваше. может и я не прав, но есть ощущение у меня, что все-таки именно предложенный мной вариант более правилен.
Johny777
30-12-2012, 21:57
Raf-9600, 100 компонетов - много,
Мой тебе добрый совет - разбей компнеты по тематической составляющей
получившиеся группы компонетов помести на страницы настройки TInputOptionWizardPage или простые страницы с чеклистбоксами на них
короче делай что-то вроде инсталла K-Lite Codec Pack который хоть и перегружен настройками, но не под каким углом не напрягает свалившейся сразу информацией
Raf-9600
30-12-2012, 23:28
100 компонетов - много »
127, если быть точнее http://i26.fastpic.ru/big/2011/0719/2b/fc34dc50ea144827810c667a06591c2b.gif
Мой тебе добрый совет - разбей компнеты по тематической составляющей »
вот так сойдёт? :)
http://img-fotki.yandex.ru/get/6211/17398782.1/0_969b0_1df3be5a_orig.jpg (http://img-fotki.yandex.ru/get/6210/17398782.1/0_969af_7848ff50_orig.jpg) http://img-fotki.yandex.ru/get/6110/17398782.1/0_969ae_1671e6c_orig.jpg (http://img-fotki.yandex.ru/get/6212/17398782.1/0_969ad_fb71bf20_orig.jpg)
У меня ещё один нубский вопрос: как сделать чтобы и на SelectTasksPage галочки тоже расставлялись в зависимости от того что указано в .ini?
И есть ли возможность сделать чтобы компоненты узнавались не по названию, а по номеру? Ибо внезапно оказалось что у меня просто туча разных компонентов с одинаковыми названиями =\
Johny777
31-12-2012, 15:36
У меня ещё один нубский вопрос: как сделать чтобы и на SelectTasksPage галочки тоже расставлялись в зависимости от того что указано в .ini? »
вкладка Support говорит нам, что на странице задач тоже самое что и на странице компонентов (только другого цвета и без границ), поэтому также как и с компонентами, только светую для простоты создать отдельную секцию в ини
ComponentsList: TNewCheckListBox;
TasksList: TNewCheckListBox;
RunList: TNewCheckListBox;
И есть ли возможность сделать чтобы компоненты узнавались не по названию, а по номеру? »
можно - по индексу. Например добавленные сверху вниз 10 компонентов, где у первого идекс равен 0, а у 10-го индекс - 9
только чтоб у тебя не было, что один компонент добавляется в зависимости от чего-то, а то компонента в середине нет, номера сдвинутся и получится ерунда
WizardForm.ComponentsList.Checked[индекс]
вот так сойдёт? »
вечный Diablo 2 пакуешь! Хорошо! :)
типа того, например у диаблы знаю 3 озвучки и разные варианты видео - на одну страницу, кастомную
короче я б сделал так (комментарии внутри)
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
DisableProgramGroupPage=yes
UninstallDisplayIcon={app}\MyProg.exe
OutputDir=.
[Components]
Name: a; Description: a
Name: b; Description: b
Name: c; Description: c
Name: d; Description: d
[Files]
; это озвучка от Фаргуса
Source: {fonts}\*; DestDir: {app}; Flags: external; Check: Install('озвучка от 8бит');
; это субтитры от Фаргуса
Source: {fonts}\*; DestDir: {app}; Flags: external; Check: Install('видео от 8бит');
; заметь отмечаемые радиокнопки с одинаковым тестом - от 8бит
[ Code]
var
SoundPage, VideoPage, SubtittlesPage: TInputOptionWizardPage;
function Install(sText: String): boolean;
begin
case sText of
'озвучка от 8бит': Result := SoundPage.SelectedValueIndex = 0;
'видео от 8бит': Result := VideoPage.SelectedValueIndex = 0;
end;
end;
procedure InitializeWizard;
begin
SoundPage := CreateInputOptionPage(wpSelectComponents, 'Выбор озвучки', '', '', True, False);
with SoundPage do
begin
SubCaptionLabel.Caption := 'Озвучка:';
AddEx('от 8бит', 0, True);
SelectedValueIndex := 0; /// по дефолту отмечен
Values[0] := GetIniValue('Sound', '8bit', '', iFile) = 'true';
AddEx('от Фаргуса', 0, True);
Values[1] := GetIniValue('Sound', 'Fargus', '', iFile) = 'true'; // итд. Советую для звука, видео и субтитров сделать по отдельной секции в ини
AddEx('от "русский проект"', 0, True);
AddEx('английская', 0, True);
end;
VideoPage := CreateInputOptionPage(SoundPage.ID, 'Выбор видео', '', '', True, False);
with VideoPage do
begin
SubCaptionLabel.Caption := 'Видео:'
AddEx('от 8бит', 0, True);
AddEx('от Фаргуса', 0, True);
AddEx('от "русский проект"', 0, True);
AddEx('английская', 0, True);
SelectedValueIndex := 1;
end;
SubtittlesPage := CreateInputOptionPage(VideoPage.ID, 'Выбор субтитров', '', '', True, False);
with SubtittlesPage do
begin
SubCaptionLabel.Caption := 'Субтитры:'
AddEx('английские', 0, True);
AddEx('русские', 0, True);
SelectedValueIndex := 1;
end;
end;
ещё советую изучить \Inno Setup 5\Examples\Example_NewCheckListBox.iss
Raf-9600
31-12-2012, 15:50
типа того, например у диаблы знаю 3 озвучки и разные варианты субтитров - на одну страницу, кастомную
короче я б сделал так (комментарии внутри) »
У меня выбор из семи языков и шести русских озвучек. Плюс к тому огромная куча других компонентов, как к примеру выбор музыки или модификаций типа PlugY и MultiRes. Если я всю эту араву начну делить на страницы, то это будет ахтунг.
Соль в том, что по умолчанию я уже выбрал лучший набор компонентов, и предполагается что юзер там вообще ничего не должен менять. Как показала практика, юзер действительно не хочет ничего выбирать, ему бы лиш бы быстрее на кнопку "далее" покликать, что в твоём варианте более затруднительно чем в моём :)
Кстати, если поклонник этой игры, можешь скачать, оценить - (удалено) (мне сказали что варез тут запрещён, так что кому нужна ссылка - в ЛС пишите.)
© OSzone.net 2001-2012
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.