Интерактивное вычисление формул в программах на Delphi

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

В этом случае у программистов есть два способа решения задачи:

1. Написать свой собственный интерпретатор формул.

2. Использовать один из имеющихся серверов автоматизации: Microsoft Excel, PTC MathCAD и т.п.

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

Математических формул много (синусы, арксинусы, экспоненты, степени, логарифмы и т.д.), формы их записи бывают разные (СУММ, SUM), поэтому, написать достойный интерпретатор формул задача далеко не простая и трудоемкая.

Следует обратить внимание и на то, что в реальной жизни таких программ, которые требуют интерпретатор формул, не много. Затратив значительные усилия и время на написание собственного интерпретатора, в дальнейшем его применение при написании прикладных программ будет ограниченным и неоправданным с материальной точки зрения.

Учитывая сказанное, Вашему вниманию предлагается второй способ решения задачи с использованием математических возможностей распространенного сервера автоматизации Microsoft Excel.

Одной из замечательных возможностей многозадачных операционных систем является поддержка взаимодействия и обмена информацией между различными программами. Приложение MS Excel представляет собой объект-сервер, который может управляться внешней программой.

Сервер автоматизации представляет собой программу, которая может управляться внешней программой – контроллером автоматизации. Сервером в данном случае является MS Excel, а контроллер разрабатывается программистом. На этапе выполнения программы серверу автоматизации передается команда в виде строки с формулой, предварительно записанной в переменную. Формула автоматически вычисляется сервером и результат передается обратно в программу.

Программа-контроллер должна выполнить следующие функции:

1. Проверить, запущено приложение MS Excel или нет.

2. Если приложение не запущено, запустить его.

3. Выполнить ряд необходимых манипуляций, связанных с введением формулы.

4. Закрыть документ и приложение.

5. Очистить память.

Написаны две небольшие программы, контроллеры автоматизации, а ниже показаны их коды, подготовленные в Delphi XE2. Версия Delphi значения не имеет.

Программа 1. Формула вводится с помощью чисел, без переменных

Программа для вычислений формулы без переменных Рис.1. Программа для вычислений формулы без переменных

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

unit Unit1;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
Vcl.StdCtrls, ComObj, Vcl.ExtCtrls, SHELLAPI;
type
TForm1 = class(TForm)
GroupBox1: TGroupBox;
GroupBox3: TGroupBox;
Edit5: TEdit;
GroupBox5: TGroupBox;
Button1: TButton;
Label2: TLabel;
Label3: TLabel;
Label7: TLabel;
GroupBox4: TGroupBox;
Edit6: TEdit;
procedure Button1Click(Sender: TObject);
procedure Label3Click(Sender: TObject);
private
{ Private declarations }
public
procedure Formula(Formula_Text:string; var Formula_Val:variant;
var flag1:integer);
end;

var
Form1: TForm1;

implementation
{$R *.dfm}
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
var
Rezultat:variant;
flag:integer;
STR1:STRING;
l,i:integer;
begin
flag:=1;
Str1:=AnsiUpperCase(Edit5.Text);
l:=Length(Str1);
for i:=1 to l do if str1[i]=',' then Str1[i]:='.';
Formula(STR1, Rezultat, flag);
if flag=1 then
begin
Edit6.Text:=Rezultat;
end;
end;

procedure TForm1.Formula(Formula_Text: string; var Formula_Val: variant;
var flag1: integer);
var
E, Sheet, MyCell:Variant;
Code:integer;
rez:real;
begin
flag1:=0;
if Formula_Text[1]<>'=' then Formula_Text:='='+Formula_Text;

try
// Если Excel загружен, то подключиться к нему
E:=GetActiveOLEObject('Excel.Application');
except
// Иначе Создать объект MS Excel
E:=CreateOLEObject('Excel.Application');
end;
E.WorkBooks.Add;            // Добавить книгу MS Excel
Sheet:=E.Sheets.Item[1];    // Перейти на первую страницу книги
MyCell:=Sheet.Cells[1,1];   // Определить ячейку для занесения формулы
MyCell.Value:=Formula_Text; // Заносим формулу
Formula_Val:=MyCell.Value;  // Вычисляем формулу
if (VarIsFloat(Formula_Val)=false) or (VarIsNumeric(Formula_Val)=false) then
begin
MessageDlg('Внимание! Ошибка в формуле: ', mtWarning, [mbOk], 0, mbOk);
flag1:=0;
end
else
begin
flag1:=1;                //расчет выполнен правильно, без ошибок
end;
E.DisplayAlerts:=False;
try
E.Quit;                   // Выйти из созданного Excel
E:=UnAssigned;            // Освободить память
except
end;
end;

//===============================Гиперссылка====================================
//Гиперссылку помещаем в свойство метки Hint,
//ставим синий цвет метки,
//создаем обработчик события на нажатие метки
procedure TForm1.Label3Click(Sender: TObject);
begin
if (Sender is TLabel) then with (Sender as Tlabel) do
ShellExecute(Application.Handle,PChar('open'),PChar(Hint),PChar(0),
nil,SW_NORMAL);
end;
//==============================================================================
end.    //Конец модуля

=============================================================================================

Рис.2. Исходный текст основного модуля программы 1 (контроллера автоматизации)

Скачать программу…

Программа 2. Формула вводится с помощью чисел, с переменными X1, …, X4

Программа для вычислений формулы c переменными

Рис.3. Программа для вычислений формулы c переменными

В первую строку вводятся значения переменных X1, X2, X3, X4. Если переменная равна нулю, можно ничего не вводить в соответствующее поле.

Во вторую строку вводится формула по правилам записи, принятым в Microsoft Excel с переменными (X1, X2,.., X4), в третьей строке отображается результат, полученный от сервера автоматизации. Приведем текст исходного модуля программы 2:

unit Unit1;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics,  Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
Vcl.StdCtrls, ComObj, Vcl.ExtCtrls, SHELLAPI;

type
TForm1 = class(TForm)
GroupBox1: TGroupBox;
GroupBox2: TGroupBox;
Label1: TLabel;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Edit4: TEdit;
GroupBox3: TGroupBox;
Edit5: TEdit;
GroupBox4: TGroupBox;
Edit6: TEdit;
GroupBox5: TGroupBox;
Button1: TButton;
Label2: TLabel;
Label3: TLabel;
Label7: TLabel;
procedure Button1Click(Sender: TObject);
procedure Label3Click(Sender: TObject);
<strong>private</strong>
{ Private declarations }
public
procedure Formula(X1,X2,X3,X4:real; Formula_Text:string;
var Formula_Val:variant; var flag1:integer);
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
var
Rezultat:variant;
flag:integer;
STR1:STRING;
l,i:integer;
X1, X2, X3, X4: real;
begin
flag:=1;
if Edit1.Text<>'' then X1:=StrToFloat(Edit1.Text) else X1:=0;
if Edit2.Text<>'' then X2:=StrToFloat(Edit2.Text) else X2:=0;
if Edit3.Text<>'' then X3:=StrToFloat(Edit3.Text) else X3:=0;
if Edit4.Text<>'' then X4:=StrToFloat(Edit4.Text) else X4:=0;
Str1:=AnsiUpperCase(Edit5.Text);
l:=Length(Str1);
for i:=1 to l do if str1[i]=',' then Str1[i]:='.';
Formula(X1,X2,X3,X4, STR1, Rezultat, flag);
if flag=1 then
begin
Edit6.Text:=Rezultat;
end;
end;

procedure TForm1.Formula(X1, X2, X3, X4 : real; Formula_Text: string;
var Formula_Val: variant; var flag1: integer);
var
E, Sheet, MyCell_X1, MyCell_X2, MyCell_X3, MyCell_X4,MyCell_Y:Variant;
Code:integer;
rez:real;
begin
flag1:=0;
if Formula_Text[1]&lt;&gt;'=' then Formula_Text:='='+Formula_Text;
try
// Если Excel загружен, то подключиться к нему
E:=GetActiveOLEObject('Excel.Application');
except
// Иначе Создать объект MS Excel
E:=CreateOLEObject('Excel.Application');
end;
E.WorkBooks.Add;             // Добавить книгу MS Excel
Sheet:=E.Sheets.Item[1];     // Перейти на первую страницу книги
MyCell_X1:=Sheet.Cells[1,24];// Определить ячейку для занесения переменной X1
MyCell_X1.Value:=X1;         // Заносим переменную X1
MyCell_X2:=Sheet.Cells[2,24];// Определить ячейку для занесения переменной X2
MyCell_X2.Value:=X2;         // Заносим переменную X2
MyCell_X3:=Sheet.Cells[3,24];// Определить ячейку для занесения переменной X3
MyCell_X3.Value:=X3;         // Заносим переменную X3
MyCell_X4:=Sheet.Cells[4,24];// Определить ячейку для занесения переменной X4
MyCell_X4.Value:=X4;         // Заносим переменную X4
// Определить ячейку для занесения формулы и считывания результата
MyCell_Y:=Sheet.Cells[1,1];
MyCell_Y.Value:=Formula_Text;// Заносим формулу
Formula_Val:=MyCell_Y.Value; // Вычисляем формулу
if (VarIsFloat(Formula_Val)=false) or (VarIsNumeric(Formula_Val)=false) then
begin
MessageDlg('Внимание! Ошибка в формуле: ', mtWarning, [mbOk], 0, mbOk);
flag1:=0;
end
else
begin
flag1:=1;                 //расчет выполнен правильно, без ошибок
end;
E.DisplayAlerts:=False;
try
E.Quit;                    // Выйти из созданного Excel
E:=UnAssigned;             // Освободить память
except
end;
end;

//===============================Гиперссылка====================================
//Гиперссылку помещаем в свойство метки Hint,
//ставим синий цвет метки,
//создаем обработчик события на нажатие метки
procedure TForm1.Label3Click(Sender: TObject);
begin
    if (Sender is TLabel) then with (Sender as Tlabel) do
    ShellExecute(Application.Handle,PChar('open'),PChar(Hint),
    PChar(0),nil,SW_NORMAL);
end;
//==============================================================================
end.

Рис.4. Исходный текст основного модуля программы 2 (контроллера автоматизации)

Скачать программу…

Александр Малыгин

Объект обсуждения - программное обеспечение для выполнения автоматизированного конструкторского и технологического проектирования, разработки управляющих программ, вопросы, связанные с разработкой прикладных САПР.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *