Заметки
Несколько способов скрыть MDIChild окно

:: Меню ::
:: На главную ::
:: FAQ ::
:: Заметки ::
:: Практика ::
:: Win API ::
:: Проекты ::
:: Скачать ::
:: Секреты ::
:: Ссылки ::

:: Сервис ::
:: Написать ::

:: MVP ::

:: RSS ::

Яндекс.Метрика


Результат, к которому приводит попытка скрыть MDIChild окно штатными средствами Delphi, всегда заканчивается одинаково – а именно сообщением “Cannot hide an MDI Child Form”. Мне это кажется странным, ведь в желании спрятать MDIChild окно нет ничего криминального. Найти причину такого поведения оказалось несложно – она кроется в методе VisibleChanging класса TCustomForm, который объявлен следующим образом:

TCustomForm = class(...)
{...}
protected
  procedure VisibleChanging; override;
{...}
end;

implementation

procedure TCustomForm.VisibleChanging;
begin
  if (FormStyle = fsMDIChild) and Visible and (Parent = nil) then
    raise EInvalidOperation.Create(SMDIChildNotVisible);
end;

Первое, что бросается в глаза, метод объявлен с директивой override. Но что же он перекрывает? А перекрывает он пустой динамический метод класса TControl, который вызывается из метода SetVisible этого же класса:

TControl = class(...)
private
  procedure SetVisible(Value: Boolean);
{...}
protected
  procedure VisibleChanging; dynamic;
{...}
public
  property Visible: Boolean read FVisible write SetVisible stored IsVisibleStored default True;
{...}
end;

implementation

procedure TControl.VisibleChanging;
begin
end;

procedure TControl.SetVisible(Value: Boolean);
begin
  if FVisible <> Value then
  begin
    VisibleChanging;
    FVisible := Value;
    Perform(CM_VISIBLECHANGED, Ord(Value), 0);
    RequestAlign;
  end;
end;

Все это наводит на пару мыслей. Метод динамический – значит мы можем его перекрыть. А так как этот метод ничего, кроме генерации исключения, не делает, перекрывающий метод нужно просто оставить пустым.

//
// MDIChild
//
type
  TForm2 = class(TForm)
  protected
    procedure VisibleChanging; override;
  end;
 
implementation
 
procedure TForm2.VisibleChanging;
begin
end;

//
// MDIForm
//
uses
  {...,} Unit2;

procedure TForm1.Button1Click(Sender: TObject);
begin
   Form2.Hide;
end;

Другая мысль – нужно скрыть форму не используя свойства Visible и метода Hide. В этом нам поможет API функция ShowWindow. При этом нам не нужно вносить в код MDIChild формы никаких изменений.

//
// MDIForm
//
uses
  {...,} Unit2;

procedure TForm1.Button1Click(Sender: TObject);
begin
   ShowWindow( Form2.Handle, SW_HIDE );
end;

А теперь давайте вернемся к коду метода VisibleChanging, и внимательно посмотрим в каком случае генерируется исключение. Для генерации исключения должно выполняться 3 условия.

1. У скрываемой формы свойство FormStyle должно иметь значение fsMDIChild. Что ж, тут ничего не поделаешь, ведь именно такую форму нам и нужно скрыть.

2. Она должна быть видимой. И тут все логично, ведь вряд ли кому то придет в голову скрывать форму, которая и так не видна.

3. У формы не должно быть “родителя”. Вот на этом и можно сыграть, чтобы обмануть метод VisibleChanging!

Это может выглядеть примерно так:

//
// MDIForm
//
uses
  {...,} Unit2;

procedure TForm1.Button1Click(Sender: TObject);
begin
   Form2.Parent := Application.MainForm;
   // или так
   // Form2.Parent := TWinControl.Create( nil );
   Form2.Hide;
end;

Вот оно, очередное подтверждение всем вам хорошо известной истины – если нельзя, но очень хочется, то можно! Успехов в программировании!


При использовании материала - ссылка на сайт обязательна