четверг, 16 октября 2014 г.

Dialog Wizard в Delphi

Задался вопросом создания "мастера" для чего нибудь.

Наш мастер должен иметь страницу приветствия, финиша и разные прочие страницы.

Страница приветствия

Рабочая страница

Итак, что мы делаем. На форму кидаем TopPanel (TPanel), pcWizard (TPageControl), Bevel1 (TBevel) и ActionList. Для начала разберемся с верхней панелью. Я поместил там lblCaption и lblHint (TLabel), а также картинку.
В pcWizard создаем 3 закладки: tsWelcome, tsFinish, tsPage1. Первые две будут очень похожие, даже одинаковые, только текст будет разный. На них помещает текст приветствия и какую-нибудь подходящую картинку. Картинка желательно большего размера по высоте.
В ActionList создаем 3 события (Action): acNext, acBack, acCancelDone.
В TBevel размещаем 3 кнопки: "Назад", "Далее", "Отмена". И присваиваем им соответствующие события из ActionList.
На странице tsPage1 для демонстрации разместим один CheckBox. Переход далее будет осуществляться только если он отмечен.

Ну вот и все с дизайном. Переходим к коду.

При старте нашей формы нам нужно убрать шапки с закладок. В FormCreate напишем.

type
  TDialogWizard = class(TForm)
   .....
  public  
    procedure CheckWhenPageActive;
...
 end;

procedure TDialogWizard.FormCreate(Sender: TObject);
var
  i: Integer;
begin
  for i := 0 to pcWizard.PageCount - 1 do
    pcWizard.Pages[i].TabVisible := False;
  pcWizard.ActivePage := tsWelcome;
  CheckWhenPageActive;
end;

Здесь мы скрыли все заголовки со страниц, установили стартовую и запустили процедуру CheckWhenPageActive. Она отвечает за отображение верхней панели, текста на ней и отображение кнопок навигации. Вот ее код:

var
  DialogWizard: TDialogWizard;
  PNextPage, PPrevPage: ^TTabSheet;

.....

procedure TDialogWizard.CheckWhenPageActive;
var
  PPage : ^TTabSheet;
begin
  PPage := @(pcWizard.ActivePage);
  if PPage^ = tsWelcome then
    begin
      TopPanel.Visible := false;
      PNextPage := @tsPage1;
      PPrevPage := nil;
    end;

  if PPage^ = tsFinish then
    begin
      TopPanel.Visible := false;
      PNextPage := nil;
      PPrevPage := nil;
      acCancelDone.Caption := 'Готово';
    end;

  if PPage^ = tsPage1 then
    begin
      TopPanel.Visible := true;
      PNextPage := @tsFinish;
      PPrevPage := nil;
      lblCaption.Caption := '';
      lblHint.Caption := '';
    end;

  acNext.Visible := PNextPage <> nil;
  acBack.Visible := PPrevPage <> nil;
end;

В процедуре проверяем какая страница активна. Для каждой страницы нам необходимо указать предыдущую страницу и следующую (указатели PNextPage, PPrevPage: ^TTabSheet). Можно было бы и просто менять с помощью SelectNextPage, но тогда их надо в дизайнере отсортировать по очередности. А если надо пропустить? Я решил указывать это для каждой страницы. Если какая-либо ссылка не указана, то и соответствующая кнопка не будет видна. Например: tsWelcome - видна кнопка далее, следующая страница tsPage1. А у tsPage1, появилась возможность отображать заголовок и комментарий к странице. TopPanel.Visible := true - говорит, о том, что верхняя панель будет показана.

Итак мы знаем какая страница будет следующей. Начинаем обрабатывать переход.

procedure TDialogWizard.acNextExecute(Sender: TObject);
begin
  if AllowChangePage then
   begin
    pcWizard.ActivePage := PNextPage^;
    CheckWhenPageActive;
   end;
end;

Функция AllowChangePage проверяет, можно ли переходить к следующей странице. Если она принимает значение TRUE, то переходим к следующей странице. Вот ее код:

type
  TDialogWizard = class(TForm)
   .....
  private
    function AllowChangePage: boolean;
    .....
end;

function TDialogWizard.AllowChangePage: boolean;
var
  PPage : ^TTabSheet;
begin
  result := true;
  PPage := @(pcWizard.ActivePage);

   if PPage^ = tsPage1 then
    begin
      result := CheckBox1.Checked;
    end;
end;

Помните на tsPage1 мы кидали CheckBox. Так вот эта функция проверяет отмечен он или нет, и либо разрешает, либо запрещает переход.

С переходом назад проще. Просто переходим назад.

procedure TDialogWizard.acBackExecute(Sender: TObject);
begin
  pcWizard.ActivePage := PPrevPage^;
  CheckWhenPageActive;
end;

Осталась кнопка "Отмена/Готово". Тут тоже все просто.

procedure TDialogWizard.acCancelDoneExecute(Sender: TObject);
begin
  if pcWizard.ActivePage <> tsFinish then
    close
  else
    begin
      // Тут что-то делаем.
      close;
    end;
end;

Если страница не последняя (tsFinish), то закрываем мастер, а нет можем выполнить отмену произведенных операций к примеру и закрыть.

Ну вот и все. Подведет итог.
Мы имеем 2 процедуры в которых отрабатывается страница:
CheckWhenPageActive - Определяем что показывать, а что нет. + Навигация.
AllowChangePage - Делаем проверку на странице.

Что-то делать в мастере можно по ходу выполнения в процедуре AllowChangePage, либо создать еще страницу, ну скажем tsProgress и делать все на ней. Но опять же в процедуре AllowChangePage. Можно организовать отмену каких-либо операций в процедуре acCancelDoneExecute.

Ну что же, удачи.

Исходник проекта DialogWizard