Вопрос Как добавить описание под картинку через botva2? [Или: вывод изображения и описания через botva2]

Andreo Fadio

Старожил
Опять я со своим 125% масштабом:acute: Как пофиксить?
и участок получения размера изображения:
Код:
  ComponentImg:=pImgLoad(ComponetForm.Handle, FileName, 0,0,0,0, False, False);
  ImgGetPosition(ComponentImg, Get_Left, Get_Top, Get_Width, Get_Height);
Лучше переписать на сам Inno Setup: Ссылка на пост

Тогда можно будет использовать:
Код:
ComponentImg:=pImgLoad(ComponetForm.Handle, FileName, ScaleX(0),ScaleY(0),ComponetForm.Width,ComponetForm.Height, True, False);
Чтобы растянуть картинку при увеличение формы
 

Andreo Fadio

Старожил
Этот код не стал работать на 6.2, выдал ошибку "Unknown identifier 'WrapTimerProc' ". Не подошло....
Так надо задать индификатор (и тащить библиотеку InnoCallBack.dll или CallbackCtrl.dll) или поменять (для Inno Setup 6.0 и выше):
Код:
WrapTimerProc(@..., 4)
на
Код:
CreateCallback(@...)
 

Toni12

Новичок
Так надо задать индификатор (и тащить библиотеку InnoCallBack.dll или CallbackCtrl.dll) или поменять (для Inno Setup 6.0 и выше):
Код:
WrapTimerProc(@..., 4)
на
Код:
CreateCallback(@...)
Библиотека и так подгружена, осталось от прошлых скриптов.
CreateCallback(@...)
Так же ошибку выдал.
 

Toni12

Новичок
Наконец-то дома. По сути сейчас на руках такой вариант скрипта, но без текстового описания, зато компилится на 6.2.

Был 2, но я его случайно удалил из-за путаницы в файлах...
 

Вложения

Andreo Fadio

Старожил
Библиотека и так подгружена, осталось от прошлых скриптов.
CreateCallback(@...)
Так же ошибку выдал.
Там полный код выглядит так:
Код:
[Setup]
AppName=My Application
AppVersion=1.5
CreateAppDir=no

[Components]
Name: comp1; Description: "Компонент 1";
Name: comp2; Description: "Компонент 2";
Name: comp3; Description: "Компонент 3";

[Files]
Source: "Main.bmp"; Flags: dontcopy
Source: "Additional.bmp"; Flags: dontcopy
Source: "Help.bmp"; Flags: dontcopy

[code]
var
  LastMouse: TPoint;
  CompLabel: TLabel;
  CompImage: TBitmapImage;
  LoadingImage: Boolean;

function GetCursorPos(var lpPoint: TPoint): BOOL;
  external 'GetCursorPos@user32.dll stdcall';
function SetTimer(hWnd: longword; nIDEvent, uElapse: LongWord; lpTimerFunc: LongWord): LongWord;
  external 'SetTimer@user32.dll stdcall';
function ScreenToClient(hWnd: HWND; var lpPoint: TPoint): BOOL;
  external 'ScreenToClient@user32.dll stdcall';
function ClientToScreen(hWnd: HWND; var lpPoint: TPoint): BOOL;
  external 'ClientToScreen@user32.dll stdcall';
function ListBox_GetItemRect(
  const hWnd: HWND; const Msg: Integer; Index: LongInt; var Rect: TRect): LongInt;
  external 'SendMessageW@user32.dll stdcall';

const
  LB_GETITEMRECT = $0198;
  LB_GETTOPINDEX = $018E;

function FindControl(Parent: TWinControl; P: TPoint): TControl;
var
  Control: TControl;
  WinControl: TWinControl;
  I: Integer;
  P2: TPoint;
begin
  for I := 0 to Parent.ControlCount - 1 do
  begin
    Control := Parent.Controls[I];
    if Control.Visible and
       (Control.Left <= P.X) and (P.X < Control.Left + Control.Width) and
       (Control.Top <= P.Y) and (P.Y < Control.Top + Control.Height) then
    begin
      if Control is TWinControl then
      begin
        P2 := P;
        ClientToScreen(Parent.Handle, P2);
        WinControl := TWinControl(Control);
        ScreenToClient(WinControl.Handle, P2);
        Result := FindControl(WinControl, P2);
        if Result <> nil then Exit;
      end;

      Result := Control;
      Exit;
    end;
  end;

  Result := nil;
end;

function PointInRect(const Rect: TRect; const Point: TPoint): Boolean;
begin
  Result :=
    (Point.X >= Rect.Left) and (Point.X <= Rect.Right) and
    (Point.Y >= Rect.Top) and (Point.Y <= Rect.Bottom);
end;

function ListBoxItemAtPos(ListBox: TCustomListBox; Pos: TPoint): Integer;
var
  Count: Integer;
  ItemRect: TRect;
begin
  Result := SendMessage(ListBox.Handle, LB_GETTOPINDEX, 0, 0);
  Count := ListBox.Items.Count;
  while Result < Count do
  begin
    ListBox_GetItemRect(ListBox.Handle, LB_GETITEMRECT, Result, ItemRect);
    if PointInRect(ItemRect, Pos) then Exit;
    Inc(Result);
  end;
  Result := -1;
end;

procedure HoverComponentChanged(Index: Integer);
var
  Description: string;
  Image: string;
  ImagePath: string;
begin
  case Index of
    0: begin Description := 'This is the description of Main Files'; Image := 'main.bmp'; end;
    1: begin Description := 'This is the description of Additional Files'; Image := 'additional.bmp'; end;
    2: begin Description := 'This is the description of Help Files'; Image := 'help.bmp'; end;
  else
    Description := 'Move your mouse over a component to see its description.';
  end;
  CompLabel.Caption := Description;

  if Image <> '' then
  begin
    { The ExtractTemporaryFile pumps the message queue, prevent recursion }
    if not LoadingImage then
    begin
      LoadingImage := True;
      try
        ImagePath := ExpandConstant('{tmp}\' + Image);
        if not FileExists(ImagePath) then
        begin
          ExtractTemporaryFile(Image);
        end;
        CompImage.Bitmap.LoadFromFile(ImagePath);
      finally
        LoadingImage := False;
      end;
    end;
    CompImage.Visible := True;
  end
    else
  begin
    CompImage.Visible := False;
  end;
end;

procedure HoverTimerProc(H: LongWord; Msg: LongWord; IdEvent: LongWord; Time: LongWord);
var
  P: TPoint;
  Control: TControl;
  Index: Integer;
begin
  GetCursorPos(P);
  if P <> LastMouse then { just optimization }
  begin
    LastMouse := P;
    ScreenToClient(WizardForm.Handle, P);

    if (P.X < 0) or (P.Y < 0) or
       (P.X > WizardForm.ClientWidth) or (P.Y > WizardForm.ClientHeight) then
    begin
      Control := nil;
    end
      else
    begin
      Control := FindControl(WizardForm, P);
    end;

    Index := -1;
    if (Control = WizardForm.ComponentsList) and
       (not WizardForm.TypesCombo.DroppedDown) then
    begin
      P := LastMouse;
      ScreenToClient(WizardForm.ComponentsList.Handle, P);
      Index := ListBoxItemAtPos(WizardForm.ComponentsList, P);
    end;

    HoverComponentChanged(Index);
  end;
end;

procedure InitializeWizard();
begin
  SetTimer(0, 0, 50, CreateCallback(@HoverTimerProc));

  CompLabel := TLabel.Create(WizardForm);
  CompLabel.Parent := WizardForm.SelectComponentsPage;
  CompLabel.Left := WizardForm.ComponentsList.Left;
  CompLabel.Width := (WizardForm.ComponentsList.Width - ScaleX(16)) div 2;
  CompLabel.Height := ScaleY(64);
  CompLabel.Top := WizardForm.ComponentsList.Top + WizardForm.ComponentsList.Height - CompLabel.Height;
  CompLabel.AutoSize := False;
  CompLabel.WordWrap := True;

  CompImage := TBitmapImage.Create(WizardForm);
  CompImage.Parent := WizardForm.SelectComponentsPage;
  CompImage.Top := CompLabel.Top;
  CompImage.Width := CompImage.Width;
  CompImage.Height := CompLabel.Height;
  CompImage.Left := WizardForm.ComponentsList.Left + WizardForm.ComponentsList.Width - CompLabel.Width;

  WizardForm.ComponentsList.Height := WizardForm.ComponentsList.Height - CompLabel.Height - ScaleY(8);
end;

И он изначально подстроен под 6.0 и выше.
 

Toni12

Новичок
Там полный код выглядит так:
Код:
[Setup]
AppName=My Application
AppVersion=1.5
CreateAppDir=no

[Components]
Name: comp1; Description: "Компонент 1";
Name: comp2; Description: "Компонент 2";
Name: comp3; Description: "Компонент 3";

[Files]
Source: "Main.bmp"; Flags: dontcopy
Source: "Additional.bmp"; Flags: dontcopy
Source: "Help.bmp"; Flags: dontcopy

[code]
var
  LastMouse: TPoint;
  CompLabel: TLabel;
  CompImage: TBitmapImage;
  LoadingImage: Boolean;

function GetCursorPos(var lpPoint: TPoint): BOOL;
  external 'GetCursorPos@user32.dll stdcall';
function SetTimer(hWnd: longword; nIDEvent, uElapse: LongWord; lpTimerFunc: LongWord): LongWord;
  external 'SetTimer@user32.dll stdcall';
function ScreenToClient(hWnd: HWND; var lpPoint: TPoint): BOOL;
  external 'ScreenToClient@user32.dll stdcall';
function ClientToScreen(hWnd: HWND; var lpPoint: TPoint): BOOL;
  external 'ClientToScreen@user32.dll stdcall';
function ListBox_GetItemRect(
  const hWnd: HWND; const Msg: Integer; Index: LongInt; var Rect: TRect): LongInt;
  external 'SendMessageW@user32.dll stdcall';

const
  LB_GETITEMRECT = $0198;
  LB_GETTOPINDEX = $018E;

function FindControl(Parent: TWinControl; P: TPoint): TControl;
var
  Control: TControl;
  WinControl: TWinControl;
  I: Integer;
  P2: TPoint;
begin
  for I := 0 to Parent.ControlCount - 1 do
  begin
    Control := Parent.Controls[I];
    if Control.Visible and
       (Control.Left <= P.X) and (P.X < Control.Left + Control.Width) and
       (Control.Top <= P.Y) and (P.Y < Control.Top + Control.Height) then
    begin
      if Control is TWinControl then
      begin
        P2 := P;
        ClientToScreen(Parent.Handle, P2);
        WinControl := TWinControl(Control);
        ScreenToClient(WinControl.Handle, P2);
        Result := FindControl(WinControl, P2);
        if Result <> nil then Exit;
      end;

      Result := Control;
      Exit;
    end;
  end;

  Result := nil;
end;

function PointInRect(const Rect: TRect; const Point: TPoint): Boolean;
begin
  Result :=
    (Point.X >= Rect.Left) and (Point.X <= Rect.Right) and
    (Point.Y >= Rect.Top) and (Point.Y <= Rect.Bottom);
end;

function ListBoxItemAtPos(ListBox: TCustomListBox; Pos: TPoint): Integer;
var
  Count: Integer;
  ItemRect: TRect;
begin
  Result := SendMessage(ListBox.Handle, LB_GETTOPINDEX, 0, 0);
  Count := ListBox.Items.Count;
  while Result < Count do
  begin
    ListBox_GetItemRect(ListBox.Handle, LB_GETITEMRECT, Result, ItemRect);
    if PointInRect(ItemRect, Pos) then Exit;
    Inc(Result);
  end;
  Result := -1;
end;

procedure HoverComponentChanged(Index: Integer);
var
  Description: string;
  Image: string;
  ImagePath: string;
begin
  case Index of
    0: begin Description := 'This is the description of Main Files'; Image := 'main.bmp'; end;
    1: begin Description := 'This is the description of Additional Files'; Image := 'additional.bmp'; end;
    2: begin Description := 'This is the description of Help Files'; Image := 'help.bmp'; end;
  else
    Description := 'Move your mouse over a component to see its description.';
  end;
  CompLabel.Caption := Description;

  if Image <> '' then
  begin
    { The ExtractTemporaryFile pumps the message queue, prevent recursion }
    if not LoadingImage then
    begin
      LoadingImage := True;
      try
        ImagePath := ExpandConstant('{tmp}\' + Image);
        if not FileExists(ImagePath) then
        begin
          ExtractTemporaryFile(Image);
        end;
        CompImage.Bitmap.LoadFromFile(ImagePath);
      finally
        LoadingImage := False;
      end;
    end;
    CompImage.Visible := True;
  end
    else
  begin
    CompImage.Visible := False;
  end;
end;

procedure HoverTimerProc(H: LongWord; Msg: LongWord; IdEvent: LongWord; Time: LongWord);
var
  P: TPoint;
  Control: TControl;
  Index: Integer;
begin
  GetCursorPos(P);
  if P <> LastMouse then { just optimization }
  begin
    LastMouse := P;
    ScreenToClient(WizardForm.Handle, P);

    if (P.X < 0) or (P.Y < 0) or
       (P.X > WizardForm.ClientWidth) or (P.Y > WizardForm.ClientHeight) then
    begin
      Control := nil;
    end
      else
    begin
      Control := FindControl(WizardForm, P);
    end;

    Index := -1;
    if (Control = WizardForm.ComponentsList) and
       (not WizardForm.TypesCombo.DroppedDown) then
    begin
      P := LastMouse;
      ScreenToClient(WizardForm.ComponentsList.Handle, P);
      Index := ListBoxItemAtPos(WizardForm.ComponentsList, P);
    end;

    HoverComponentChanged(Index);
  end;
end;

procedure InitializeWizard();
begin
  SetTimer(0, 0, 50, CreateCallback(@HoverTimerProc));

  CompLabel := TLabel.Create(WizardForm);
  CompLabel.Parent := WizardForm.SelectComponentsPage;
  CompLabel.Left := WizardForm.ComponentsList.Left;
  CompLabel.Width := (WizardForm.ComponentsList.Width - ScaleX(16)) div 2;
  CompLabel.Height := ScaleY(64);
  CompLabel.Top := WizardForm.ComponentsList.Top + WizardForm.ComponentsList.Height - CompLabel.Height;
  CompLabel.AutoSize := False;
  CompLabel.WordWrap := True;

  CompImage := TBitmapImage.Create(WizardForm);
  CompImage.Parent := WizardForm.SelectComponentsPage;
  CompImage.Top := CompLabel.Top;
  CompImage.Width := CompImage.Width;
  CompImage.Height := CompLabel.Height;
  CompImage.Left := WizardForm.ComponentsList.Left + WizardForm.ComponentsList.Width - CompLabel.Width;

  WizardForm.ComponentsList.Height := WizardForm.ComponentsList.Height - CompLabel.Height - ScaleY(8);
end;

И он изначально подстроен под 6.0 и выше.

Думал я где-то ошибся, но нет, он действительно не выводит текст и изображение у меня
 

Andreo Fadio

Старожил
@Toni12, вот вам рабочее решение (напримере кода от Nemko) по выводу формы с описанием и картинкой для любых версий inno:

2 варианта для botva и на расширенной версии от Leserg
Размер высоты участка текста регулируется через #define HeightInfo "желаемое число высоты"
 

Вложения

Последнее редактирование:

Toni12

Новичок
@Toni12, вот вам рабочее решение (напримере кода от Nemko) по выводу формы с описанием и картинкой для любых версий inno:

2 варианта для botva и на расширенной версии от Leserg
Размер высоты участка текста регулируется через #define HeightInfo "желаемое число высоты"
Спасибо! Первый вариант на Ботве подошёл)
 

Toni12

Новичок
Не знаю зачем это здесь, но пусть будет.
Закинул пару комментариев. (Место изменения подложки под текстом и автоматическое масштабирование текста в рамке)
 

Вложения

Andreo Fadio

Старожил
и автоматическое масштабирование текста в рамке
не надо вывешивать свойства масштабирование на обновление окна, а добавить в сам задаваемый элемент:
Код:
ComponetLabel:= TLabel.Create(ComponetForm);
  with ComponetLabel do
  begin
    Parent:= ComponetForm;
    Caption:= '';
    AutoSize := True;   // Перенос строки
    WordWrap:= True;     //
    Transparent:= True; //
  end;
 
Последнее редактирование:

Cyberworm

Новичок
Просматривал на днях ветку ISDone ради полезной информации и случайно наткнулся на эту форму компонентов. Естественно стало интересно на чём она подготовлена. Я так понял, что там botva2 не задействована. Есть ли интерпретация данной формы под стиль modern с использованием превью изображений jpg/png? Хотелось бы её поковырять в Inno Setup VCL ради интереса.

Пример.jpg
 

Shegorat

Lord of Madness
Администратор
Есть ли интерпретация данной формы под стиль modern с использованием превью изображений jpg/png? Хотелось бы её поковырять в Inno Setup VCL ради интереса.
Что-то вроде этого . На форуме есть несколько реализаций, поищите
 

Cyberworm

Новичок
Что-то вроде этого . На форуме есть несколько реализаций, поищите
На 45-й строчке компилятор выдаёт ошибку, мол неизвестный тип Area: TItemArea и соответственно весь блок procedure ShowCompDescription(Sender: TObject; X, Y, Index: Integer; Area: TItemArea); уже не рабочий. С чем может быть связана данная проблема?
 

Andreo Fadio

Старожил
@Cyberworm, нет такого функционала в чистой inno и расширенной от leserg, пример чисто для китайской версии.
 

Cyberworm

Новичок
@Cyberworm, нет такого функционала в чистой inno и расширенной от leserg, пример чисто для китайской версии.
Значит только один выход в этом случае - это botva2. Главное теперь подогнать размер блоков описания компонентов и их превью под WizardStyle=modern
 

Cyberworm

Новичок
Спасибо, всё работает. Правда пришлось немного повозиться с габаритами блоков ради WizardStyle=modern
Компоненты.jpg
Тем не менее Info Picture Form считаю более продвинутым (или универсальным) решением за счёт вызова внешней функции просмотра кастомного разрешения и прикрученного к картинке текста. И самый главный плюс, что в наличии имеется готовая форма для Inno Setup VCL. Поэтому всего скорей буду его использовать для переработки старого русификатора к игре Arma: Cold War Assault, который в бородатые времена был собран в NSIS. Ещё иногда смотрю в сторону FMXInno, но там сдерживающим фактором является то, что его используют для репаков. Я этим не промышляю, так что насколько целесообразно использовать комплекс FMXInno для русификации игр?
 
Сверху