Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Не получили письмо с кодом активации?

Официальный форум Simple-Scada.

Автор Тема: Как грамотнее выстроить проект?  (Прочитано 1246 раз)

torchinsky

  • Новичок
  • *
  • Сообщений: 13
    • Просмотр профиля
Доброго времени суток коллеги!
Помогите пожалуйста лучше сориентировать на начальном этапе проекта. (первый проект на SimpleScada)

Дано: объект пищевой промышленности, разделенный на 3 идентичные части, за работу которого отвечают 3 контроллера (в каждом свой OPC; по контроллеру на каждую часть). В каждой части имеется 12 модулей с кучей датчиков, алярмов, контролов и установок (настроек) + агрегаторная (по 4 компрессора + обвязки с кучей датчиков, алярмов, контролов и установок (настроек)).

Что хочу: чтобы это работало на simpleScada.

Чего не хочу: говнокодить и копиппастить. Нет желания рисовать, грубо говоря, 36 одинковых форм.... (я такую ошибку по незнаю совершил когда HMI панель для модуля рисовал...12 форм... и в каждой что то менять...ужас)

До чего докопался:
Вариант первый: хотел использовать штатные Page и Subpage.

  • Модуль 1
    • Камера 1
    • Камера 2
       
  • Модуль 2
    • Камера 1
    • Камера 2

Но, как я понял, каждый Page и Subpage - это отдельные экземляры. Т.е. нельзя создать свой базовый Page/Subpage и при открытии скриптом просто подпихивать ему нужные мне переменные. Единственный Выход в таком случае это создавать свое Окно во весь экран и открывать его при переходе на SubPage и передавать ему переменные. но выглядит это костылем каким то...тем более что окно можно закрыть, а запретить закрытие не нашел как сделать (хотя было бы достаточно просто убрать "крестик"). Та и в общем при таком способе надо за многим следить...в общем костыль.

Вариант второй: Почти все тоже самое, ток на Page/SubPage рисовать кнопки открывающие соответствующие мне окна. Т.е. Останутся Page "Модуль 1" "Модуль 2" "Модуль 3" в них всего 3 почти одинаковых формы, на которых кнопками вызов Окна. Не так красиво как хотелось бы это выглядит... и одинаковые формы все равно остались в  нескольких экземплярах...но зато без костылей вроде.

Но в обоих случаях возникает следующий вопрос: как я понял основным механизмом для определения того, с каким параметрами необходимо что необходимо открыть, является свойство "Тэг" у элементов. И тут у меня снова 2 выбора пока просматриваются:
1) Именовать переменные как block[1-3]_Camera[1-12]_AirTemp. Номер блока тогда должен вычисляться от того, какой Page выбран...и при этом знать какой SubPage/Button нажат в последствии...и вот как 2 Тэга прокинуть в скрипт я уже не нашел...
2) Именовать переменные как сamera[1-36]_AirTemp. Такой вариант я вижу как реализовать, но такое мне просто не особо нравится....на мой вкус неоднозначность/неточность в названии переменной....Ну и придется вычислить номер камеры как то на основании сторонних переменных.

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

В общем, направьте меня пожалуйста в нужную сторону, т.к. я еще тонкостей этой системы не знаю и не могу предвидеть всех моментов. Пока склоняюсь к третьему варианту и именованию переменных как block[1-3]_Camera[1-12]_AirTemp, т.к. не вижу как решить проблемы первых двух....

Заранее спасибо)

Simple_Scada

  • Администратор
  • *****
  • Сообщений: 1165
    • Просмотр профиля
Re: Как грамотнее выстроить проект?
« Ответ #1 : 22 Июня 2020, 11:38:50 »
Здравствуйте.

Для описанного проекта с множеством однотипных объектов хорошо подошла бы система шаблонов, разработкой которой мы сейчас занимаемся. С ее помощью можно будет к примеру сделать шаблон страницы/объекта/окна и при однотипном наименовании переменных использовать шаблон для быстрого создания однотипных объектов. Но система шаблонов появится не в ближайшем будущем, т.к. для ее внедрения необходимо внести значительные изменения в работу клиента и пока не ясно сколько времени на это потребуется. Когда работа над системой шаблонов будет подходить к концу мы выпустим beta-версию для тестирования шаблонов.

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

Цитировать
Но, как я понял, каждый Page и Subpage - это отдельные экземляры. Т.е. нельзя создать свой базовый Page/Subpage и при открытии скриптом просто подпихивать ему нужные мне переменные.
Для этого можно использовать подмену переменных как мы указывали выше, но такой вариант не подойдет если в проекте будет более одного клиента. Для подмены переменных у страницы можно сделать все по аналогии с примером для окон, только скрипт назначить на событие OnEnterSubpage, тогда подмена переменных будет выполняться при переходе на страницу.

Если стандартная панель страниц не подходит, Вы можете скрыть ее и создать свою панель страниц на основе кнопок. Для этого нужно задать подстраницам однотипные имена, например SubPage1, SubPage2, SubPage3, и написать один универсальный скрипт для перехода по всем подстраницам. Для этого, у кнопки перехода на первую подстраницу установим свойство "Тэг" = 1, у кнопки перехода на вторую подстраницу "Тэг" = 2, у кнопки перехода на третью подстраницу "Тэг" = 3 и т.д. Затем, перейдем в редактор скриптов и создадим скрипт с типом события "Универсальный":
Код: (delphi)
var
  aSubPage: TM_SubPage;
begin
{ ищем подстраницу с именем SubPage + значение свойства Тэг }
  aSubPage := GetSubPageByName('SubPage' + IntToStr((Sender as TM_Button).Tag));
  if aSubPage <> nil then                      // если подстраница существует
    aSubPage.GoToSubPageClient(GetClientName); // то, перейти на нее
end.
Если в проекте имеются страницы, у которых нет подстраниц, то для таких страниц просто создайте пустую подстраницу и задайте ей однотипное имя с требуемым номером по аналогии с остальными подстраницами проекта.

torchinsky

  • Новичок
  • *
  • Сообщений: 13
    • Просмотр профиля
Re: Как грамотнее выстроить проект?
« Ответ #2 : 22 Июня 2020, 15:30:36 »
Для описанного проекта с множеством однотипных объектов хорошо подошла бы система шаблонов, разработкой которой мы сейчас занимаемся. С ее помощью можно будет к примеру сделать шаблон страницы/объекта/окна и при однотипном наименовании переменных использовать шаблон для быстрого создания однотипных объектов. Но система шаблонов появится не в ближайшем будущем, т.к. для ее внедрения необходимо внести значительные изменения в работу клиента и пока не ясно сколько времени на это потребуется. Когда работа над системой шаблонов будет подходить к концу мы выпустим beta-версию для тестирования шаблонов.

Да, чего то такого не хватает очень...

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

Эта проблема с несколькими клиентами при использовании глобальных переменных просматривалась сразу. Я даже начал искать как у клиента что то хранить. Оказывается никакого хранилища у клиента нет, а жаль)) Иногда было бы полезно. Поэтому данный вариант не подходит однозначно.

В общем я понял. Буду все сам разрисовывать руками используя Окна, т.к. совсем не хочу даже 2 раза одну и ту же форму рисовать. Это слишком плохо сказывается на поддержке. Спасибо)

pan2000

  • Постоялец
  • ***
  • Сообщений: 170
    • Просмотр профиля
Re: Как грамотнее выстроить проект?
« Ответ #3 : 23 Июня 2020, 00:50:45 »
       Здравствуйте!

Возможным вариантом наименования переменных - использование суффикса, ссылающегося на набор переменных, например:
 <имя переменной>_<номер Модуля><номер Камеры из двух цифр, начиная с 1>.
В этом случае для работы с одним общим окном (пример с двумя объектами) достаточно универсального скрипта (события "Пользователь перешел на эту страницу", "Пользователь перешел на эту подстраницу", "Пользователь закрыл окно"):
Код: (delphi)
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. Проект лишь иллюстрация к данному способу наименования переменных. (отсутствие контроля, спорный код, неоптимальность кода и т.д.)

torchinsky

  • Новичок
  • *
  • Сообщений: 13
    • Просмотр профиля
Re: Как грамотнее выстроить проект?
« Ответ #4 : 23 Июня 2020, 00:57:50 »
В общем сделал следующее. На 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х и более клиентах? Проверить не могу, т.к. никаких ключей у заказчика не взял...
Та и судя по мануалам...
Цитировать
Важно! Следует учитывать, что подмена переменных происходит одновременно на всех клиентах. Поэтому, если клиентов несколько, то использовать подмену переменных следует с осторожностью

А все потому, что днем торопился не совсем внимательно прочитал Ваш ответ...получается у меня безвыходная ситуация...
« Изменён: 23 Июня 2020, 01:09:06 от torchinsky »

torchinsky

  • Новичок
  • *
  • Сообщений: 13
    • Просмотр профиля
Re: Как грамотнее выстроить проект?
« Ответ #5 : 23 Июня 2020, 01:36:50 »
       Здравствуйте!

Возможным вариантом наименования переменных - использование суффикса, ссылающегося на набор переменных, например:
 <имя переменной>_<номер Модуля><номер Камеры из двух цифр, начиная с 1>.

Доброй ночи) Спасибо, но это само собой разумеется) Проблема в том, чтобы визуально нарисовать один некий "Объект" (окно, форма, страница, подстраница....не принципиально), и уже при его открытии указывать какие данные показывать/устанавливать. И все это при том, что клиентов более 1го...

Формально, я проблему решил через окно, но как я понял, это все при условии что 1 клиент....

Если больше 1го то как не крути придется копипастить и менять потом в 36 местах.

Ваш проект я посмотрел. Предложенное решение с вычислением тэгов - было еще в самом начале, но не нравится из за меньшей прозрачности, поэтому отбросил. Остальное - в принципе все тоже самое я и сделал, ток иначе. Но проблему 2х клиентов это не решает все равно. Ну или я чего то не понял... Что весьма не исключено.