Мастера DELPHI, Delphi programming community Рейтинг@Mail.ru Титульная страница Поиск, карта сайта Написать письмо 
| Новости |
Новости сайта
Поиск |
Поиск по лучшим сайтам о Delphi
FAQ |
Огромная база часто задаваемых вопросов и, конечно же, ответы к ним ;)
Статьи |
Подборка статей на самые разные темы. Все о DELPHI
Книги |
Новинки книжного рынка
Новости VCL
Обзор свежих компонент со всего мира, по-русски!
|
| Форумы
Здесь вы можете задать свой вопрос и наверняка получите ответ
| ЧАТ |
Место для общения :)
Орешник |
Коллекция курьезных вопросов из форумов
KOL и MCK |
KOL и MCK - Компактные программы на Delphi
 
Цены на семена газонных трав www.mir-gazonov.ru.

Невизуальное наследование форм в Delphi

Рощупкин А.В.
Уральский государственный университет путей сообщения, лаборатория математического моделирования и компьютерных технологий, Екатеринбург

Аннотация.

  В работе [1] подробно рассмотрены способы "визуального" наследование форм в Delphi с целью их повторного использования. В данной статье исследована возможность использования класса, наследника TForm, как родительского для новых форм. Этод метод удобен в случае, когда нам не важно внешнее однообразие форм, как в работе [1], а важно, чтобы поведение различных по интерфейсу форм было одинаково.

Создание класса.

  Создадим базовый класс, наследник TForm, от которого в дальнейшем будем наследовать все наши формы. Для этого в новый или существующий пакет, добавим компонент TBaseForm как это показано на рисунке 1.


Рис. 1. Создание нового компонента TBaseForm

  Для Delphi 6 в пункте Requires нашего пакета добавляем "Borland Designer IDE Package" (по умолчанию находится в C:\Program_Files\Borland\Delphi6\Lib\designide.dcp). Для Delphi 5 все для нас необходимое содержится в "Borland Visual Component Library" (он включается в пакет автоматически). В раздел uses для Delphi 5 добавляем DsgnIntf, а для Delphi 6 DesignIntf и DesignEditors. Изменим процедуру Register только что созданного компонента, так как это сделано в листинге 1.


	procedure Register;
	begin
	  RegisterCustomModule(TBaseForm, TCustomModule);
	end;

Листинг 1. Изменение процедуры Register.

Компилируем наш пакет - класс TBaseForm готов к использованию.

Использование класса.

  Для того чтобы какая-либо форма проекта была наследником класса TBaseForm, для этого в раздел uses формы нужно включить юнит BaseForm, а объявление класса новой формы class(TForm) переделать на class(TBaseForm). Затем форму нужно закрыть и снова открыть. После этого наша форма станет полноценным наследником класса TBaseForm.

Пример использования.

  Пусть перед нами стоит задача: все формы проекта должны содержать информацию о версии формы (что необходимо, когда один и тот же проект подгоняется под разных заказчиков) и отображать информацию о форме каким-либо способом.

  Для реализации этих целей изменим класс TBaseForm как это показано в листинге 2. Здесь добавлены соответствующие переменные и свойства для хранения информации о версии формы и создан механизм показа информации о форме посредством системного меню окна - добавлен новый пункт системного меню "О форме".


	/////////////////////////////////////////////////////////////
	//        описание класса базовой формы
	//        Рощупкин А.В. 2003 г.
	/////////////////////////////////////////////////////////////
	unit BaseForm;

	interface

	uses
	  Windows, Messages, SysUtils, Classes, Controls, Forms,
	  //DsgnIntf;                //при использовании Delphi5
	  DesignIntf, DesignEditors; //при использовании Delphi6

	const
	  ItmID = $00a0; //идентификатор нового пункта системного меню

	type
	  TBaseForm = class(TForm)
	  private
		FVersion: integer;          //версия формы
		FMnuItmAbout: MENUITEMINFO; //структура нового пункта меню
		FOldWndProc : Pointer;      //указатель на старую функцию обработки
									//сообщений окна (формы)
		FNewWndProc : Pointer;      //указатель на новую функцию обработки
									//сообщений окна (формы)

		// возвращает информацию о форме в виде строки
		function GetAboutString: string;

	  protected
	  public
		//конструктор
		constructor Create(AOwner: TComponent); override;
		//деструктор :)
		destructor  Destroy; override;
		//возвращает указатель на старую функцию обработки сообщений окна (формы)
		function    GetOldWindowProc: Pointer;
		//показывает информацию о форме
		procedure   ShowFormInfo;

	  published
		property Version: integer read FVersion write FVersion default 1;

	  end;

	//новую функцию обработки сообщений окна (формы)
	function  NewWndProc(wnd: HWND; Msg: UINT; wPrm: WPARAM; lPrm: LPARAM): LRESULT stdcall;
	//процедура регистрации класса
	procedure Register;

	implementation

	constructor TBaseForm.Create(AOwner: TComponent);
	begin
	   inherited;

	   //у наших окон всегда должно быть системное меню!!!
	   if not ( biSystemMenu in Self.BorderIcons ) then
		  Self.BorderIcons := Self.BorderIcons + [biSystemMenu];

	   //создаем новый пункт систменого меню, по выборе которого
	   //будет показана информация о форме
	   FMnuItmAbout.cbSize := 44;
	   FMnuItmAbout.fMask := MIIM_DATA or MIIM_ID or MIIM_STATE	or MIIM_TYPE;
	   FMnuItmAbout.fType := MFT_STRING;
	   FMnuItmAbout.fState := MFS_ENABLED;
	   FMnuItmAbout.wID := ItmID;
	   FMnuItmAbout.hSubMenu := 0;
	   FMnuItmAbout.hbmpChecked := 0;
	   FMnuItmAbout.hbmpUnchecked := 0;
	   FMnuItmAbout.dwTypeData := PChar('О форме');
	   InsertMenuItem(GetSystemMenu(Self.Handle, False), 0, True, FMnuItmAbout);

	   //регистрация новой процедуры обработки сообщений окна (формы)
	   FNewWndProc := Pointer(@NewWndProc);
	   FOldWndProc := Pointer(GetWindowLong(Self.Handle, GWL_WNDPROC));
	   SetWindowLong(Self.Handle, GWL_WNDPROC, Longint(FNewWndProc));
	end;

	destructor TBaseForm.Destroy;
	begin
	   inherited;
	end;

	function TBaseForm.GetOldWindowProc: Pointer;
	begin
	   Result := FOldWndProc;
	end;

	procedure TBaseForm.ShowFormInfo;
	var
	   InfStr: string;
	begin
	   InfStr := GetAboutString;
	   MessageBox(Self.Handle, PChar(InfStr), PChar('Сведения о форме'), MB_OK);
	end;

	function TBaseForm.GetAboutString: string;
	begin
	   Result := 'Имя класса формы:  ' + Self.ClassName + #13 +
		  'Имя формы:  ' + Self.Name + '  версия  ' + IntToStr(FVersion);
	end;

	////////////////////////////////////////////////////////////////
	// в данном примере новая процедура обработки сообщений
	// окна (формы) создана только для одного сообщения -
	// ловить выбор пункта системного меню "О форме"
	////////////////////////////////////////////////////////////////
	function NewWndProc(wnd: HWND; Msg: UINT; wPrm: WPARAM; lPrm: LPARAM): LRESULT stdcall;
	var
	   FrmHWND: HWND;
	   wctrl: TWinControl;
	   BFrm: TBaseForm;
	begin
	   Result := 0;
	   FrmHWND := wnd;
	   wctrl := FindControl(FrmHWND);
	   if ( wctrl = nil ) then Exit;
	   FrmHWND := GetParentForm(wctrl).Handle;
	   if ( FrmHWND = 0 ) then Exit;
	   BFrm := TBaseForm(FindControl(FrmHWND));
	   if ( BFrm = nil ) then
		  Exit;
	   Result := CallWindowProc(BFrm.GetOldWindowProc, wnd, Msg, wPrm, lPrm);
	   case ( Msg ) of
		  //выбран пункт системного меню "О форме"
		  WM_SYSCOMMAND :
			 begin
				if ( LOWORD(wPrm) = ItmID ) then
				begin
				   wctrl := FindControl(wnd);
				   if ( wctrl <> nil ) then
					  if ( wctrl is TBaseForm ) then
						 TBaseForm(wctrl).ShowFormInfo;
				end;
			 end;
	   end;
	end;

	procedure Register;
	begin
	  RegisterCustomModule(TBaseForm, TCustomModule);
	end;

	end.

Листинг 2.

  Теперь, наследуя все формы проекта от класса TBaseForm, мы можем сохранять версию формы и получать информацию о форме через системное меню окна (формы).

  Конечно, данным примером не исчерпывается использование данного метода. Из явных применений видятся: 1) сохранение параметров окон, например методом [2]; 2) разграничение прав доступа (если где-нибудь, например, в базе данных, мы храним права доступа к элементам окна, то эти права можно реализовать в конструкторе TBaseForm); 3) табуляция между элементами окна по нажатию клавиши Enter в TEdit (для этого нужно в NewWndProc включить соответствующий обработчик) и т.д.

  К недостаткам метода относится то, что в построенном классе TBaseForm крайне сложно будет создавать визуальные компоненты.

Приложения.

В package.zip - пакет, содержащий описание класса TBaseForm. В program.zip - пример программы, содержащий три формы, унаследованные от TBaseForm.

Список литературы

[1]
Голованов М. Повторное использование форм в Delphi // Электронная публикация: http://www.delphimaster.ru/articles/repuseforms/index.html
[2]
Ситнин Г. Маленькие хитрости: Автоматическое сохранение и восстановление свойств формы // Электронная публикация: http://www.delphimaster.ru/articles/formpropsaver.html
   Внимание! Запрещается перепечатка данной статьи или ее части без согласования с автором. Если вы хотите разместить эту статью на своем сайте или издать в печатном виде, свяжитесь с автором.
Автор статьи:  Рощупкин А.В.
  

Другие статьи Наверх


  Рейтинг@Mail.ru     Титульная страница Поиск, карта сайта Написать письмо