Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
СРЕДСТВА ВИЗУАЛЬНОГО ПРОГРАММИРОВАНИЯ.doc
Скачиваний:
13
Добавлен:
02.05.2019
Размер:
2.13 Mб
Скачать

13.5. Включение в библиотеку форм

Несмотря на то, что DLL не имеет собственной формы, с ее помощью можно вызывать формы из связанных с библиотекой модулей. Для этого в библиотеке используется ссылка uses на связанные модули-формы и объявляются экспортируемые из DLL подпрограммы, в которых реализуется вызов соответствующих форм.

В следующем примере иллюстрируется техника включения в DLL формы и использования ее в вызывающей программе.

Текст DLL

library DLLWithForm;

uses

SysUtils,

Classes,

DLLFormU in 'DLLFormU.pas' {DLLForm};

{$R *.RES}

exports

ShowModalForm, ShowForm, FreeForm;

begin

end.

Текст формы в DLL

 

unit DLLFormU;

interface

uses

Windows, Messages, SysUtils,Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Buttons;

type

TDLLForm = class (TForm) BitBtnl: TBitBtn;

BitBtn2: TBitBtn;

procedure FormClose(Sender: TObject; var Action: TCloseAction);

private

{ Private declarations }

CallForm: THandle; //Дескриптор вызывающей формы

public

{ Public declarations }

end;

// Объявление экспортируемых подпрограмм

function ShowModalForm: Integer;

procedure ShowForm(aHandle: THandle);

procedure FreeForm;

var

DLLForm: TDLLForm;

implementation

{$R *.DFM}

function ShowModalForm: Integer;

// Модальный вызов

begin

DllForm := TDllForm.Create(Application);

Result := DLLForm.ShowModal;

DLLForm.Free;

end;

procedure ShowForm(Appl, Form: THandle);

// Немодальный вызов

begin

Application.Handle := Appl; // Замена объекта

Application DllForm := TDllForm.Create(Application);

// Запоминаем дескриптор вызывающего окна для посылки

// ему сообщения о закрытии

CallForm := Form;

DLLForm.Show

end;

procedure FreeForm;

// Уничтожение формы

begin

DLLForm.Free

end; procedure TDLLForm.FormClose(Sender: TObject;

var Action: TCloseAction);

begin

if CallFormoO then

SendMessage(CallForm, wm_User, 0, 0)

end;

end.

Текст вызывающей программы

unit TestMainU;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type

TTestMain = class (TForm)

Buttoni: TButton; // Открыть в модальном режиме

Button2: TButton; // Открыть в немодальном режиме

Button3: TButton; // Закрыть окно

Label I: TLabel;

procedure ButtonlClick(Sender: TObject);

procedure Button2Click(Sender: TObject);

procedure ButtonSClick(Sender: TObject);

private

{ Private declarations } public

{ Public declarations }

procedure WMUser(var Msg: TMessage);

message WM_USER;

end;

var

TestMain: TTestMain;

implementation

{$R *.DFM}

function ShowModalForm: Integer;

External 'DLLWithForm';

procedure ShowForm(Appl, Form: THandle);

External ' DLLWithForm' ;

procedure FreeForm;

External 'DLLWithForm';

procedure TTestMain.ButtonlClick(Sender: TObject);

// Модальный вызов

begin

Button2.Enabled := False;

labell.Caption := 'ModalResult = '+IntToStr(ShowModalForm);

labell.Show; // Показываем результат вызова

Button2.Enabled := True

end;

procedure TTestMain.Button2Click(Sender: TObject);

// Немодальный вызов

begin

Buttoni.Enabled :== False;

Button2.Enabled := False;

Buttons.Enabled := True; label 1.Hide;

ShowForm(Application.Handle, Self.Handle) ;

end;

procedure TTestMain.Button3Click(Sender: TObject);

// Закрыть форму

begin

FreeForm;

Button1.Enabled := True;

Button2.Enabled := True;

Button3.Enabled := False/end;

procedure TTestMain.WMUser(var Msg: TMessage) ;

// Сообщение из формы DLL о ее закрытии

begin

Buttons.Click

end;

end.

Модуль формы DLLForm, помещенной в DLL, ссылается на стандартный модуль Forms и таким образом получает свой глобальный объект Application, который ничего “не знает” о глобальном объекте вызывающей программы (см. гл. 21). В режиме модального вызова это не имеет особого значения, т. к. модальное окно блокирует работу вызывающей программы. В режиме немодального вызова следует синхронизовать действия объектов, в противном случае минимизация главного окна, например, не приведет к минимизации окна DLL. Синхронизация достигается тем, что дескриптор объекта Application DLL заменяется на соответствующий дескриптор вызывающей программы.

При показе формы в немодальном режиме она может быть закрыта щелчком по собственной системной кнопке закрыть. В этом случае она должна каким-то образом известить вызывающую программу об этом событии. Для этого используется стандартный механизм посылки вызывающей форме Windows-сообщения. Сообщение должно иметь адрес, в роли которого используется дескриптор окна, получающего это сообщение. Вот почему вторым параметром обращения к функции ShowForm в DLL передается и в поле CallForm: запоминается дескриптор вызывающего окна. Обработчик события enclose формы проверяет это поле и, если оно определено, посылает вызывающему окну сообщение с индексом wm_user. В вызывающей программе предусмотрен обработчик этого сообщения, в котором реализуются необходимые действия.

  • Лекция 14. ОСОБЕННОСТИ РАЗРАБОТКИ МОДУЛЕЙ-ПОТОКОВ

Современные операционные системы Windows 32 обеспечивают не только многозадачность, т. е. возможность параллельной работы нескольких программ, но и многопоточность, когда в рамках одной программы организуется несколько параллельно выполняемых фрагментов (потоков), каждый из которых конкурирует с другими потоками за наиболее важный ресурс - время центрального процессора. В многопоточном режиме время ЦП выделяется для каждого процесса небольшими порциями (квантами), по истечении этого времени управление передается другому потоку и т. д. до тех пор, пока потоки не закончат свою работу. В любой работающей программе организуется как минимум один поток для команд программы. С помощью объектов класса TThread программа может создать дополнительные потоки для проведения некоторой фоновой работы (например, текстовый процессор Word создает дополнительные потоки для проверки правильности орфографии, разбивки на страницы, печати документа и т. п.).

Для создания дополнительного потока в программах Delphi предназначен специальный модуль потока в репозитории он обозначен пиктограммой Thread Obiecll). При выборе этого модуля Delphi запрашивает имя класса, который будет дочерним для основополагающего класса TThread. Необходимость наследования связана с тем, что класс TThread содержит абстрактный метод Execute, который, собственно, и должен исполняться в рамках нового потока и который, следовательно, обязан перекрываться в потомках.

После указания имени дочернего класса Delphi раскрывает дополнительный модуль с обширным комментарием и заготовкой для дочернего класса.

Например (с соответствующим переводом):

unit Unit1;

interface

uses

Classes;

type

MyThread = class(TThread)

private

{ Private declarations } protected

procedure Execute; override;

end;

implementation

{ Важно: Методы и свойства объектов из библиотеки визуальных компонентов могут использоваться только в рамках вызова метода Synchronize, например:

Synchronize(UpdateCaption);

где метод UpdateCaption должен быть подобен такому

procedure MyThread.UpdateCaption;

begin

Formi.Caption := 'Новый текст метки';

end; }

( MyThread }

procedure MyThread.Execute;

begin

{ Пожалуйста, поместите код потока в этом месте }

end;

end.

Программирование потока ничем не отличается от программирования обычной программы за одним важным исключением: поток не должен использовать методы и свойства визуальных компонен тов, которые приводят к изменению внешнего вида программа Точнее, он может это делать только при обращении к специальному методу synchronize, с помощью которого осуществляется синхронизация исполнения главного потока программы с дополнительным потоком.

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

Для ее создания сначала на пустую форму поместите панель TPpanel, очистите ее свойство caption и поместите в Align значение аlRight - эта панель предназначена для размещения редактора TSpinEdit, кнопки TButton и индикатора TGauge и всегда должна располагаться в правой части окна программы. Поместите на панель перечисленные компоненты так, как это показано на рисунке (компоненты TSpinEdit и TGuage находятся на странице samples палитры компонентов). 

Установите в свойство SpinEditl.Value 3начение 2, присвойте свойству Gaugel. Kind значение gkPie, Gaugel. BorderStyle-bsNone и Button1.Caption — 'Квадрат'.

На свободное место формы положите компонент TMemo и установите для него в свойство Align значение alСlient, а свойство Name- 'mmOutput'.

Теперь создадим обработчик события Button1.Click: при нажатии на кнопку вначале содержимое редактора SpinEdit1 возводится в квадрат до тех пор, пока отображаемое в нем значение не слишком большим (больше 10+1233). В этот момент надпись на кнопке меняется на “корень”, а нажатие на нее вычисляет корень квадратный ИЗ величины SpinEdit1.

Дважды щелкните по кнопке Button1и напишите такой код:

procedure TFormI.ButtonlClick(Sender: TObject) ;

begin

if Tag=0 then

begin

SpinEditl.Text := Float-ToStr(sqr(StrToPloat(SpinEditl.Text))) ;

if StrToFloat(SpinEditl.Text) > 1el233 then

begin

Tag := 1;

Buttoni.Caption := 'Корень'

end

end

else

begin

SpinEditl.Text := FloatToStr(sqrt(StrToFloat(SpinEditl.Text))) ;

if StrToFloat(SpinEditl.Text) < 2 then

begin

SpinEditl.Value := 2;

Tag := 0;

Button1.Caption := 'Квадрат'

end

end

end;

Таким образом, главный код программы связан с извлечением корня или возведением в квадрат величины, записанной в редакторе

SpinEditl.

Теперь создадим модуль потока, в методе Execute которого будем непрерывно формировать по 100 строк в редакторе mmOutput и показывать процент заполнения редактора с помощью индикатора Gaugel.

Выберите пиктограмму модуля потока в окне репозитория Delphi и дайте наследнику класса Thread имя ThreadDemo. Окончательный текст модуля потока представлен ниже.

unit Unit2;

interface

uses

Classes;

type

ThreadDemo = class(TThread) private

{ Private declarations } protected

S: String;

N: Integer;

procedure UpdateMemo;

procedure UpdateGauge;

procedure Execute; override;

end;

var

TDemo: ThreadDemo;

implementation

uses Uniti,SysUtils;

Important: Methods and properties of objects in VCL can only re used .in a method called using Synchronize, for example,

Synchronize(UpdateCaption);

and UpdateCaption could look like,

procedure ThreadDemo.UpdateCaption;

begin

Formi.Caption := 'Updated in a thread';

end; }

ThreadDemo }

procedure ThreadDemo.Execute;

var

j, k: Integer;

begin

repeat

S:='';

Synchronize(UpdateMemo);

for k := 0 to 99 do

begin N := k;

S : = ' ' ;

for j := 1 to 20 do

S := S+FormatFloat('00',k), Synchronize(UpdateMemo) ;

Synchronize(UpdateGauge)

end;

until False

end;

Procedure ThreadDemo.UpdateMemo;

begin

with .Form1.mmOutput.Lines do

if S=' ' then

Clear else

Add(S)

end;

Procedure ThreadDemo.UpdateGauge;

begin

Form1.Gaugel.Progress := N

end;

end.

Если вы запустите таким способом подготовленную программу, то ничего не произойдет - ведь мы еще не запустили поток. Чтобы сделать это, добавьте в модуле Unit1 главной формы ссылку uses Unit1, раскройте в окне Инспектора объектов список компонентов, выберите компонент Form1 и на его странице Event дважды щелкните по свойству onActivate, чтобы создать такой обработчик этого события:

procedure TFormI.FormActivate(Sender: TObject);

begin

TDemo := ThreadDemo.Create (False),

end;

Вот так просто запускается дополнительный поток - мы инициируем объект TDemo, передавая в его Консруктор ThreadDemo.Create

единственный параметр False (этот параметр показывает, должен ли вновь созданный поток “спать” - True или он обязан немедленно начать работу - False). Программа в любой момент может приостановить работу потока, присвоив его свойству suspended значение True, и продолжить его выполнение, присвоив этому свойству значение False. Обратите внимание - метод Execute потока вынесен в секцию protected и поэтому недоступен из основного модуля. Выполнение этого метода начинается автоматически, как только свойство suspended примет значение False.

Для обращения к свойствам и методам визуальных компонентов формы Form1 предназначен специальный метод потока Synchronize. Единственным параметром обращения к этому методу должно быть имя любой потоковой процедуры без параметров. Внутри такой процедуры разрешается обращаться к методам и свойствам визуальных компонентов. В нашем потоке две такие процедуры - UрdateMemo и updateGuage. В первой строка s добавляется к содержимому редактора mmoutput, во втором - глобальная переменная n присваивается свойству progress индикатора Gauge1. Поскольку эти процедуры не могут иметь параметров, для управления их работой приходится использовать глобальные переменные S и N.

  • Лекция 15. ТИПИЗИРОВАННЫЕ КОНСТАНТЫ И ИНИЦИИРОВАННЫЕ ПЕРЕМЕННЫЕ

    • КОНСТАНТЫ ПРОСТЫХ ТИПОВ И ТИПА STRING

    • КОНСТАНТЫ-МАССИВЫ

    • КОНСТАНТЫ-ЗАПИСИ

    • КОНСТАНТЫ-МНОЖЕСТВА

    • КОНСТАНТЫ-УКАЗАТЕЛИ

    • ИНИЦИАЦИЯ ПЕРЕМЕННЫХ

В Object Pascal допускается использование типизированных констант. Они задаются в разделе объявления констант следующим образом:

<идентификатор> : <тип> = <значение>

Здесь <идентификатор> - идентификатор константы; <тип> - тип константы; <значение> - значение константы.

Во всех версиях Delphi, кроме версии 6, типизированным константам можно присваивать другие значения в ходе выполнения программы, поэтому фактически они представляют собой переменные с начальными значениями, т. е. являются инициированными переменными.

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

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

Типизированную константу нельзя использовать в качестве значения при объявлении других констант или границ типа-диапазона.