Главная » Delphi » Компонент TddgRunButton — создание свойств

0

Если в среде  16 разрядной Windows,  помимо текущей,  требовалось запустить еще одну программу, то для этого можно было использовать функцию API WinExec(). Хо тя эта функция в среде Win32 все еще поддерживается, но использовать ее не рекомендуется. Для запуска очередного приложения теперь предлагается использовать функции API CreateProcess() и ShellExecute(). Каждый  раз применять для это го функцию API CreateProcess() довольно обременительно, поэтому  создадим  для ее замены  собственный метод ProcessExecute(), о чем и пойдет  речь ниже.

Для иллюстрации использования этого  метода  создадим  компонент TddgRunBut- ton. Его назначение заключается в запуске  приложения по щелчку  пользователя на предоставленной ему кнопке.

Компонент TddgRunButton —  идеальный пример создания свойств, проверки их значений и инкапсуляции сложных операций. Вдобавок  здесь  показано, как извлечь пиктограмму приложения из его исполняемого файла  и отобразить ее в компоненте TddgRunButton во  время  разработки. Класс  компонента TddgRunButton является производным  от  класса  компонента  TSpeedButton.  Поскольку  этот  компонент  со держит некоторые свойства, которые нежелательно делать  доступными в окне  ин спектора объектов во время  разработки, покажем, как можно  скрыть уже существую щие свойства от пользователя компонента. Конечно, эту методику  нельзя считать идеальным подходом, а в теоретическом плане  правильнее было бы создать  свой соб ственный новый компонент, и авторы вполне с этим  согласны. Однако  это  один  из тех случаев,  когда  компания Borland, при  всей  своей  безграничной мудрости, все же допустила  некоторое упущение, не предоставив промежуточного класса между ком понентами TSpeedButton и TCustomControl (последний является предком компо нента  TSpeedButton), — хотя  у всех остальных подобных компонентов они  есть.  Та ким  образом, пришлось выбирать: или  возиться с собственным компонентом, кото рый  в значительной мере  дублирует возможности TSpeedButton, или одолжить их у TSpeedButton, но скрыть при  этом  несколько ненужных свойств. Было  выбрано по следнее, но  только   по  необходимости. Между  тем,  это  хороший пример того,  на сколько  тщательно следует  продумывать возможности и методы  расширения компо нента, созданного другими разработчиками.

Код компонента TddgButton приведен в листинге 11.13.

Листинг 11.13. RunBtn.pas — исходный  код компонента TddgRunButton

unit RunBtn;

interface uses

Windows, Messages, SysUtils, Classes, Graphics, Controls,

Forms, Dialogs, StdCtrls, Buttons;

type

TCommandLine = type string;

TddgRunButton = class(TSpeedButton)

private

FCommandLine: TCommandLine;

// Свойства, скрытые от инспектора объектов

FCaption: TCaption;

FAllowAllUp: Boolean;

FFont: TFont;

FGroupIndex: Integer;

FLayOut: TButtonLayout;

procedure SetCommandLine(Value: TCommandLine);

public

constructor Create(AOwner: TComponent); override;

procedure Click; override;

published

property CommandLine: TCommandLine read FCommandLine

write SetCommandLine;

// Свойства "только для чтения" скрыты

property Caption: TCaption read FCaption;

property AllowAllUp: Boolean read FAllowAllUp;

property Font: TFont read FFont;

property GroupIndex: Integer read FGroupIndex;property LayOut: TButtonLayOut read FLayOut;

end;

implementation uses ShellAPI; const

EXEExtension = ‘.EXE';

function ProcessExecute(CommandLine: TCommandLine;

cShow: Word): Integer;

{ Этот метод инкапсулирует вызов функции CreateProcess(), создающей

новый процесс и его первичный поток. Данный метод используется в

Win32 для запуска других приложений и требует применения структур

TStartInfo и TProcessInformation. Такие структуры не

документированы в интерактивной справочной системе Delphi, но

описаны в файле справки Win32 как STARTUPINFO и

PROCESS_INFORMATION.

Параметр CommandLine указывает путь к файлу, предназначенному для

выполнения.

Параметр cShow задает константу SW_XXXX, определяющую способ

отображения окна. Это значение присваивается полю sShowWindow

структуры TStartupInfo.}

var

Rslt: LongBool;

StartUpInfo: TStartUpInfo;      // Задокументирован как STARTUPINFO

// Задокументирован как PROCESS_INFORMATION

ProcessInfo: TProcessInformation;

begin

{ Очистить содержимое структуры StartupInfo }

FillChar(StartupInfo, SizeOf(TStartupInfo), 0);

{ Инициализация структуры StartupInfo необходимыми данными.

Здесь значение константы SW_XXXX присваивается полю

wShowWindow структуры StartupInfo. При задании значения этого

поля в поле dwFlags должен быть установлен флаг

STARTF_USESSHOWWINDOW. Дополнительная информация о структуре

TStartupInfo находится в справочной документации

по системе Win32, в разделе STARTUPINFO. }

with StartupInfo do begin

cb := SizeOf(TStartupInfo); // Задать размер структуры

dwFlags := STARTF_USESHOWWINDOW or STARTF_FORCEONFEEDBACK;

wShowWindow := cShow

end;

{ Создать процесс, вызвав функцию CreateProcess(). Эта функция заполняет структуру ProcessInfo информацией о новом процессе и его первичном потоке. Подробная информация о структуре TProcessInfo содержится в документации по Win32 в

разделе PROCESS_INFORMATION. }

Rslt := CreateProcess(PChar(CommandLine), nil, nil, nil, False,

NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInfo);

{ Если Rslt равно true, значит, вызов функции CreateProcessпрошел успешно. В противном случае GetLastError вернет код ошибки. }

if Rslt then

with ProcessInfo do begin

{ Ожидание запуска процесса. }

WaitForInputIdle(hProcess, INFINITE);

CloseHandle(hThread); // Освободить дескриптор hThread

CloseHandle(hProcess);// Освободить дескриптор hProcess

Result := 0;                  // Result равен 0, запуск успешный

end

else Result := GetLastError; // Присвоить Result код ошибки.

end;

function IsExecutableFile(Value: TCommandLine): Boolean;

{ Данный метод позволяет проверить, представляет ли Value

исполняемый файл. Для этого расширение файла проверяется на

соответствие строке ‘EXE’ }

var

Ext: String[4];

begin

Ext := ExtractFileExt(Value);

Result := (UpperCase(Ext) = EXEExtension);

end;

constructor TddgRunButton.Create(AOwner: TComponent);

{ Конструктор устанавливает стандартные значения свойств размеров в

соответствии 45×45 }

begin

inherited Create(AOwner);

Height := 45;

Width       := 45;

end;

procedure TddgRunButton.SetCommandLine(Value: TCommandLine);

{ Данный метод записи присваивает полю FCommandLine значение Value,

но только если это значение является корректным именем исполняемого

файла. Он также устанавливает для компонента TddgRunButton

пиктограмму файла, заданного параметром Value. }

var

Icon: TIcon;

begin

{ Вначале проверяется, находится ли Value в заданном месте и

действительно ли он представляет собой исполняемый файл. }

if not IsExecutableFile(Value) then

Raise Exception.Create(Value+’ is not an executable file.’);

if not FileExists(Value) then

Raise Exception.Create(‘The file: ‘+Value+’ cannot be found.’);

FCommandLine := Value;      // Сохранение Value в FCommandLine

{ Отображение пиктограммы файла, заданного параметром Value, в пиктограмме компонента TddgRunButton. Это требует создания экземпляра класса TIcon для помещения пиктограммы. Затем онакопируется оттуда в свойство Canvas компонента TddgRunButton.

Для получения пиктограммы приложения следует вызвать

функцию API Win32 ExtractIcon(). }

Icon := TIcon.Create; // Создать экземпляра класса TIcon

try

{ Выделение пиктограммы из файла приложения. }

Icon.Handle := ExtractIcon(hInstance, PChar(FCommandLine), 0);

with Glyph do begin

{ Установка свойств TddgRunButton таким образом, чтобы

пиктограмму из Icon можно было скопировать в этот

компонент.

Сначала очистить содержимое Canvas на случай, если прежде

там находилась другая пиктограмма. }

Canvas.Brush.Style := bsSolid;

Canvas.FillRect(Canvas.ClipRect);

{ Установить ширину и высоту пиктограммы }

Width := Icon.Width;

Height := Icon.Height;

// Отобразить пиктограмму на поверхности TddgRunButton.

Canvas.Draw(0, 0, Icon);

end;

finally

Icon.Free; // Удалить экземпляр TIcon

end;

end;

procedure TddgRunButton.Click;

var

WERetVal: Word;

begin

inherited Click; // Вызов унаследованного метода Click

{ Выполнение метода ProcessExecute и проверка возвращаемого им

значения. Если возвращаемое значение не равно 0, то передается

исключение, поскольку произошла ошибка. Исключение выводит на

экран сообщение о коде ошибки. }

WERetVal := ProcessExecute(FCommandLine, sw_ShowNormal);

if WERetVal <> 0 then begin

raise Exception.Create(‘Error executing program. Error Code:;’

+ IntToStr(WERetVal));

end;

end;

end.Компонент TddgRunButton обладает свойством CommandLine типа String. Зна

чение этого свойства хранится в закрытом поле FCommandLine.

CОВЕТ

Определение  типа  TCommandLine заслуживает  отдельного  обсуждения.  В  данном случае используется следующий синтаксис:

TCommandLine = type string;

Такое определение предлагает компилятору рассматривать TCommandLine как уни- кальный тип и вместе с тем совместимый с остальными строковыми типами. Новый тип может получить собственную информацию о типах времени выполнения и собст- венный редактор свойства. Эта же технология может быть использована и для других типов, например:

TMySpecialInt = type Integer;

Создание редактора для свойства CommandLine описано в следующей главе. Пока не бу-

дем отвлекаться на это, так как данная тема сложная и ее придется обсудить особо.

Методом  записи для свойства CommandLine является метод  SetCommandLine(). Были  представлены также  две  вспомогательные  функции: IsExecutableFile() и ProcessExecute().

Функция IsExecutableFile() по расширению переданного ей файла  проверяет, является ли он исполняемым.

Источник: Тейксейра, Стив, Пачеко, Ксавье.   Borland Delphi 6. Руководство разработчика. : Пер.  с англ. — М. : Издательский дом “Вильямс”, 2002. —  1120 с. : ил. — Парал. тит. англ.

По теме:

  • Комментарии