Здравствуйте.
Для описанного проекта с множеством однотипных объектов хорошо подошла бы система шаблонов, разработкой которой мы сейчас занимаемся. С ее помощью можно будет к примеру сделать шаблон страницы/объекта/окна и при однотипном наименовании переменных использовать шаблон для быстрого создания однотипных объектов. Но система шаблонов появится не в ближайшем будущем, т.к. для ее внедрения необходимо внести значительные изменения в работу клиента и пока не ясно сколько времени на это потребуется. Когда работа над системой шаблонов будет подходить к концу мы выпустим beta-версию для тестирования шаблонов.
Сейчас, в отсутствие системы шаблонов можно только копировать страницы созданные ранее и заменять переменные у объектов. Также, сейчас имеется возможность подмены переменных у объектов, как рассмотрено в этом примере (https://simple-scada.com/help/script/varsubs.html), но такой способ будет работать только если в проекте используется не более 1 клиента. Если клиентов более одного или предполагается в будущем использовать более одного клиента, то вариант с подменой переменных не подойдет, потому что подмена переменных происходит одновременно на всех клиентах и будет возникать ситуация когда пользователь при просмотре одного объекта будет видеть переменные другого объекта, т.к. во втором клиенте выбрали другую страницу.
Но, как я понял, каждый Page и Subpage - это отдельные экземляры. Т.е. нельзя создать свой базовый Page/Subpage и при открытии скриптом просто подпихивать ему нужные мне переменные.
Для этого можно использовать подмену переменных как мы указывали выше, но такой вариант не подойдет если в проекте будет более одного клиента. Для подмены переменных у страницы можно сделать все по аналогии с примером для окон (https://simple-scada.com/help/script/varsubs.html), только скрипт назначить на событие OnEnterSubpage, тогда подмена переменных будет выполняться при переходе на страницу.
Если стандартная панель страниц не подходит, Вы можете скрыть ее и создать свою панель страниц на основе кнопок. Для этого нужно задать подстраницам однотипные имена, например SubPage1, SubPage2, SubPage3, и написать один универсальный скрипт для перехода по всем подстраницам. Для этого, у кнопки перехода на первую подстраницу установим свойство "Тэг" = 1, у кнопки перехода на вторую подстраницу "Тэг" = 2, у кнопки перехода на третью подстраницу "Тэг" = 3 и т.д. Затем, перейдем в редактор скриптов и создадим скрипт с типом события "Универсальный" (https://simple-scada.com/help/script/event-types.html):
var
aSubPage: TM_SubPage;
begin
{ ищем подстраницу с именем SubPage + значение свойства Тэг }
aSubPage := GetSubPageByName('SubPage' + IntToStr((Sender as TM_Button).Tag));
if aSubPage <> nil then // если подстраница существует
aSubPage.GoToSubPageClient(GetClientName); // то, перейти на нее
end.
Если в проекте имеются страницы, у которых нет подстраниц, то для таких страниц просто создайте пустую подстраницу и задайте ей однотипное имя с требуемым номером по аналогии с остальными подстраницами проекта.
Здравствуйте!
Возможным вариантом наименования переменных - использование суффикса, ссылающегося на набор переменных, например:
<имя переменной>_<номер Модуля><номер Камеры из двух цифр, начиная с 1>.
В этом случае для работы с одним общим окном (пример с двумя объектами) достаточно универсального скрипта (события "Пользователь перешел на эту страницу", "Пользователь перешел на эту подстраницу", "Пользователь закрыл окно"):
const ObjName: array [1..2] of string[10] = ('Field1', 'Button1'); // связывание переменной с объектом окна
VarName: array [1..2] of string[10] = ('Var1_', 'iButt1_'); // для большого числа переменных удобнее двумерный массив (как в 3 окнах)
var i: integer;
begin
for i := 1 to 2 do // привязать реальные переменные к объектам окна
GetObjectByName(ObjName[i]).Variable := GetVariableByName(string(VarName[i]) + IntToStr(Sender.Tag));
GetPageByName('Set' + IntToStr((Sender.Tag div 100) * 100)).Tag := Sender.Tag; // запомнить набора для этой страницы (
Window1.Tag := Sender.Tag; // запомнить для восстановления окна после попытки закрыть "незакрываемое" окно.
Window1.ShowAll;
end. Существенным является определение тегов и название страниц/подстраниц:
- для подстраниц постоянное значение равное индексу набора;
- для страниц - начальное значение равное индексу первой подстраницы;
- для окна - начальное ноль, к переменным подключен первый набор;
- в данном примере страница - Set<номер Модуля>00, подстраница - Set<номер Модуля><номер Камеры>.
Добавление "новых" окон сводится к созданию нового набора переменных и добавлению подстраницы или страницы.
Вариант с 3 окнами - скрипт аналогичного вида с событием "Изменились переменные" для переменных "Вектор выбора подстраницы" (в примере iSelPage<номер Модуля>) у каждой страницы. По имени и значению переменной скрипт формирует индекс набора и далее привязывает переменные.
Добавление новых подстраниц - создание нового набора данных и добавление новой кнопки на странице, добавление новых страниц - создание новой переменной "Вектор выбора подстраницы", связывания ее с кнопками выбора подстраниц, добавление имен объектов страницы в таблицу, связывающую имена переменных и объектов. И кое-что по мелочи.
Поместить объекты на новую страницу можно копированием с предыдущей, и при удачном выборе имен объектов, после копирования легко поправить таблицу, начальной привязки переменных не требуется (выполнится при инициализации переменных "Вектор ...").
1. Сравнить варианты можно в проекте из вложения, однако вариант с "постоянно хлопающим окном" (в т.ч. и при смене подстраницы в этом примере) менее предпочтителен для оператора.
2. Для объектов требующих связывание данных, кроме переменной (таблица, список с уникальными значениями, ...) в скрипте потребуется анализ (и соответствующий код) либо типа, либо имени объекта.
3. Проект лишь иллюстрация к данному способу наименования переменных. (отсутствие контроля, спорный код, неоптимальность кода и т.д.)
В общем сделал следующее. На Page добавил 3 кнопки с Тэгами 1 - 3. Создал Окно. Создал следующий универсальный скрипт (пока префиксы переменных по модулям не делал)
var
callerIndex, counter, offset : integer;
tempText : TM_Text;
tempField : TM_Field;
begin
callerIndex := (Sender as TM_Button).Tag;
offset := (callerIndex - 1) * 12;
BlockInfoWindow.Title := "Обзор работы камер Модуля " + IntToStr(callerIndex);
for counter := 1 to 12 do begin
tempText := GetTextByName("TextCamNameInfo" + IntToStr(counter));
if tempText <> nil then tempText.Text := "Камера " + IntToStr(tempText.Tag + offset);
tempField := GetFieldByName("WBlockInfoAirTemp" + IntToStr(counter));
if tempField <> nil then tempField.Variable := GetVariableByName("test_var" + IntToStr(tempField.Tag));
end;
BlockInfoWindow.ShowClient(GetClientName);
end.
Вроде работает, но смущает то, что окно открывается и через долю секунды ток перерисовывается....мелькает типа. Что навело меня на мысль....а точно ли такой подход нормально отработает одновременно на 2х и более клиентах? Проверить не могу, т.к. никаких ключей у заказчика не взял...
Та и судя по мануалам...
Важно! Следует учитывать, что подмена переменных происходит одновременно на всех клиентах. Поэтому, если клиентов несколько, то использовать подмену переменных следует с осторожностью
А все потому, что днем торопился не совсем внимательно прочитал Ваш ответ...получается у меня безвыходная ситуация...