Выложить проект и пояснить, где в нем динамические тексты, которые не выводятся.
Вид для печати
У меня при редактировании визуализаций через некоторое время перестает возможность удалять элементы. Не работает кнопка "DEL" и правая кнопка мыши не открывает контекстное меню. В меню "Правка" тоже не активен пункт "Удаление". При этом тексты в элементах могу удалять. Перемещать и менять размеру тоже можно. Лечиться перезагрузкой CS. На разных проектах пробовал. CS3.5.14. Что может быть?
В окне "Устройства" тоже правая кнопка мыши не работает, не открывает меню.
Это похоже сугубо ваша особенность. Я нечто подобное наблюдал при работе через Anydesk с 4к мониторами но во всех программах, возможно у вас тоже что-то подобное.
Добрый день, коллеги!
Возник следующий вопрос. В коде программы используется функциональный блок усреднения значений,который вызывается раз в секунду. После усреднения необходимо округлить значение до определенного разряда, в данном примере до одной значащей цифры после запятой. Для этого используются функция ROUND библиотеки OSCAT_BASIC. Результат округления отображается в визуализации с форматированием %s, и вроде бы всё работает как надо, но в определенный момент времени с периодичностью примерно раз в три секунды к результату округления добавляется 0.00001.Вложение 55901 Первое число - выходное значение блока усреднения, второе число результат работы функции Round( где вход это выход с блока усреднения и N=1). Оба числа это Real. Почему округление иногда срабатывает некорректно и как можно решить этот вопрос?
Добрый день.
В онлайн-отладке в редакторе кода значения переменных отображаются корректно или тоже с округлением?
Для этого можно обойтись без функций - просто использовать спецификатор %.1fЦитата:
После усреднения необходимо округлить значение до определенного разряда, в данном примере до одной значащей цифры после запятой
Или нужно округлить не только для визуализации, но и для дальнейшей обработки в программе?
В редакторе кода отображается корректно, да округление также необходимо для дальнейших вычислений, спецификатор %.1f не совсем подходит, потому что в некоторых случаях необходимо, чтобы разряд менялся в зависимости от диапазона. Также он неудобен для визуализации потому что при большом целом числе будет отображаться 100000.0 или при %.2f 100000.00, а хотелось бы отбросить не значащие нули, если это возможно.
Ещё попробовал функцию из РП "Архивация"(стр.53) называется REAL_TO_FWSTRING, она округляет корректнее то есть без периодического появления 0.00001 , но опять же при заданном количестве значащих цифр после запятой=0, значение будет в любом случае выглядеть "X.0", то есть ноль не отбросится.
Я думаю, у вас отклоение появляется при конвертации в строку (потому что %s) - не уверен, что его вообще можно избежать, это особенности типа с плавающей точкой.
А из кода программы возможно менять спецификатор? Что-нибудь в духе %.iF, где i - переменная int
Добрый день!
Есть главная визуализация Visualisation, на ней элемент Набор вкладок (3 вкладки, соответственно, на каждой по визуализации: Visu1, Visu2, Visu3). Переменная VisuElems.CURRENTVISU в любом случае, независимо от того, какая вкладка, принимает значение 'Visualisation'.
Существует ли способ из программы узнать, какая вкладка активна? Без использования переменной-переключателя.
Добрый день.
Для начала потребуется получить контекст клиента (pClientData) - см. этот пример:
https://ftp.owen.ru/CoDeSys3/21_Exam...projectarchive
После этого в программе:
Если у вас используется VisuElems.CURRENTVISU - то контексты клиентов должны совпадать, так что достаточно работать с одним из них.Код:VAR
itfFrameManager: VisuElems.VisuElemBase.IFrameManager;
aiCurrentFrameIndex: ARRAY [1..VISU_MAX_NUMBER_OF_CLIENTS] OF INT; // индексы текущих экранов фреймов для всех клиентов
END_VAR
itfFrameManager := VisuElems.VisuElemBase.g_VisuManager.GetFrameManager();
FOR := 1 TO VISU_MAX_NUMBER_OF_CLIENTS DO
aiCurrentFrameIndex[i] := itfFrameManager.GetSelectedVisu('MyVisu.MyFrameName', apClientData[i]);
// MyVisu - название экрана, на котором расположен фрейм
// MyFrameName - имя элемента, заданное в параметра фрейма (первый параметр в списке)
// apClienData - массив с контекстами клиентов
END_FOR
Потому что округлять Real так себе затея. Округляйте WString или в INT перекидывайте. Вот код для генерации WString с округлением:
Собственно большая его часть из OSCATPHP код:FUNCTION fRealToWString : WSTRING
VAR_INPUT
In: REAL;
iDec: INT; (*Количество знаков после запятой*)
END_VAR
VAR
diValue: DINT;
i: INT;
END_VAR
VAR CONSTANT
sDot: WSTRING(1):=".";
END_VAR
(*Значение с плавающей точкой*)
iDec:= LIMIT(0,iDec,6);
diValue:= LREAL_TO_DINT(ABS(In) * EXPT(10, iDec));
IF ABS(In) * EXPT(10, iDec) - DINT_TO_REAL(diValue) > 0.5 THEN
diValue:= diValue + 1;
END_IF
fRealToWString:= DINT_TO_WSTRING(diValue);
FOR i:= WLEN(fRealToWString) TO iDec DO
fRealToWString:= WCONCAT("0", fRealToWString);
END_FOR
IF iDec > 0 THEN
fRealToWString:= WINSERT(fRealToWString, sDot, WLEN(fRealToWString) - iDec);
END_IF
IF In < 0 THEN
fRealToWString:= WCONCAT("-", fRealToWString);
END_IF
Да, спасибо, тоже её находил, но посчитал её слишком ресурсозатратной для ПЛК при большом количестве округляемых значений (могу ошибаться, мб ощутимой разницы и нет) в сравнении например с этой.
PHP код:FUNCTION REAL_TO_FWSTRING : wstring
VAR_INPUT
rVar: REAL;
usiPrecision: USINT; //кол-во знаков после запятой
END_VAR
VAR
uliVar: ULINT;
lrVar: lreal;
END_VAR
uliVar:= LREAL_TO_ULINT((rVar)* EXPT(10,usiPrecision));
lrVar := ULINT_TO_LREAL(uliVar)/EXPT(10,usiPrecision);
REAL_TO_FWSTRING:= LREAL_TO_WSTRING(lrVar);
что касается чисто отображения можно сделать немного по-другому, используя динамические тексты для текстового поля:
создать динамический лист для переменной вида:
id текст
0 - %d //отображение без цифр после запятой
1 - %.1f // с одним знаком после запятой
2 - %.2f // 2
3 - %.3f // 3
и т.д.
Только потребуется присвоить для каждого текстового поля переменную с типом отображения и добавить некоторый обработчик в код программы - условия выбора того или иного отображения.
Что касается появления некоторого 'приращения' у значения, это связано с кодированием типа REAL, также сталкивался с подобным.
Собс-но с этим же связаны трудности сравнения переменных REAL на равенство, рекомендуется (кажется это было у OSCAT) сравнивать через некотрую дельту, а не в лоб.
Т.е. код ниже не корректен, т.к. возможны отличия в последних значащих знаках и условие никогда не выполнится (при этом при отладке может казаться что все ок, будет отображаться как будто два одинаковых числа)
rTmp1 :REAL;
rTmp2 :REAL;
IF rTmp1 = rTmp2 <...>
Соот-но рекомендуется в этом случае сравнивать таким образом
IF ABS(rTmp1 - rTmp2) < 0000.1 <...> // дельта в зависимости от требуемой точности
Добрый день.
Посмотрите, пожалуйста.
Нужно, что бы на каждом подключаемом WEB-клиенте открывались одни и те же страницы и созданные мной диалоги, что и на первом клиенте, на котором могли быть произведены уже какие-либо действия в интерфейсе.
Погуглив, пришел к такой конструккции:
VAR pClientData: POINTER TO VisuElems.VisuStructClientData;
Далее с помощью
VisuElems.g_ClientManager.BeginIteration();
pClientData := VisuElems.g_ClientManager.GetNextClient();
по числу pClientData > 0 определяем, что произошло изменение числа активных клиентов.
При увеличении числа активных клиентов, для всех клиентов применяем в цикле сначала открытие нужной страницы, а затем и открытие диалога (информация об открытых хранится в паре массивов), причем эту "синхронгизацию" начинам не сразу, а спустя секунду после подключения клиента, что бы уже загрузиласть стартовая страница.
Диалоги вызываются так:
VisuElems.g_ClientManager.BeginIteration();
REPEAT
pClientData := VisuElems.g_ClientManager.GetNextClient();
IF pClientData > 0 THEN
itfDialogManager:=VisuElems.VisuElemBase.g_VisuMan ager.GetDialogManager();
itfMyDialog := itfDialogManager.GetDialog('имя нужного диалога');
itfDialogManager.OpenDialog(itfMyDialog, pClientData, TRUE, null);
END_IF
UNTIL pClientData = 0
END_REPEAT;
Вопрос. Почти работает - но только для двух вкладок в браузере. Попытка третьего подключения приводит с исключению, которое ведет куда-то вглубь библиотеки визуализации. Может, это потому, что я повторно пытаюсь открыть уже открытые диалоги на более ранних двух клиентах (маловероятно) ? А может, я вообще изобретаю велосипед и есть более простые и правильные способы такой синхронизации интерфейсов?
Да - специфика задачи. У меня все страницы и диалоги открываются программно. В дизайненре форм к кнопкам никакие действия по открытию страниц или диалогов привязать не получится. Еще среда рекомендует использовть более новую библиотеку VU. Но по ней не нашел особо документации и примеров. Да и не в этом дело, наверное...
Добрый день.Цитата:
А может, я вообще изобретаю велосипед и есть более простые и правильные способы такой синхронизации интерфейсов?
Еще среда рекомендует использовть более новую библиотеку VU. Но по ней не нашел особо документации и примеров.
Посмотрите это видео: https://youtu.be/_kA9WVtbg3A
Спасибо, посмотрел. Но диалог почему-то не открывается. И ошибок при исполнении вроде не возникает. В среде только начал работать.
Подскажите, я вообще правильно делаю, в главном цикле, может вызываться при каждом подключении: MyOpenDialog(itfClientFilter:=VU.Globals.AllClient s, xExecute:=TRUE, sDialogName:=sVisuName, xModal:=TRUE);
sVisuName на момент вызова имеет правильное имя диалога - 'Visualization_3'
Да, но он что-то вообще пока не открывается, увы. Не понимаю пока, почему...
А вообще, после того, как открытие заработает, возможна такая логика - предположим, подключился очередной клиент, и я опять выполняю эту строку, и на новом клиенте открывается диалог?
Ясно, спасибо. Пока попробую сам...
Хм. В порядке бреда сделал вот так:
MyOpenDialogFlag:=FALSE;
MyOpenDialog(itfClientFilter:=VU.Globals.AllClient s, xExecute:=MyOpenDialogFlag, sDialogName:=sVisuName, xModal:=TRUE);
IF Find(Show_SubPage_Name[Byte_1-Digital_Offset],'Visual')<>0 THEN
MyOpenDialogFlag:=TRUE;
sVisuName:=Show_SubPage_Name[Byte_1-Digital_Offset];
MyOpenDialog(itfClientFilter:=VU.Globals.AllClient s, xExecute:=MyOpenDialogFlag, sDialogName:=sVisuName, xModal:=TRUE);
END_IF
И вроде заработало. Десять вкладок - полет нормальный.
Евгений, большое спасибо за помощь. А не подскажите, через VU экраны (не диалоги) визуализации ведь тоже можно открывать ? Там где-то есть аналог SetMainVisu ?
См. VU.fbChangeVisu
Понял, VU.FbChangeVisu. Спасибо!
Добрый день!
А как думаете - почему может быть такая штука. Не критично, но не приятно. У меня стоит задача открыть для вновь подключаещегося клиента ту же экранную форму и диалог, что и у ранее подключенного.
Для начала я просто попробовал открывать диалоги на всех клиентах, но при этом возникало в журнале предупреждение, что что превышено число экземпляров формы диалога. Что, в обшем, логично. Если, скажем, на момент подключения был уже один клиент - одно сообщение, если два - то два сообщения и т.д. Частично проблема решилась превентивным закрытием диалога и открытием его вновь (на глаз это не заметно вообще):
MyCloseDialog(itfClientFilter:=VU.Globals.AllClien ts, xExecute:=FALSE, sDialogName:=MyVisuName);
MyCloseDialog(itfClientFilter:=VU.Globals.AllClien ts, xExecute:=TRUE, sDialogName:=MyVisuName);
MyOpenDialog(itfClientFilter:=VU.Globals.AllClient s, xExecute:=FALSE, sDialogName:=MyVisuName, xModal:=TRUE);
MyOpenDialog(itfClientFilter:=VU.Globals.AllClient s, xExecute:=TRUE, sDialogName:=MyVisuName, xModal:=TRUE);
Но. При числе клиентов больше 4х стабильно опять возникает предупреждение в журнале, что превышено число экземпляров формы диалога. Причем вываливается их сразу пачка, штук 20-30.
Если клиентов четыре и менее, все пока стабильно, может работать часами при активном использовании интерфейса.
Вероятно, лучше было бы конечно вести учет указателей pClientData, тем более, что для обнаружения новых клиентов я пользуюсь этим старым методом. Но все равно не понятно. Тем более, что в настройках визуализации стоит макс. число соединений - 100. Конечно, у меня вряд ли будет более 2-3 клиентов визуализации одновременно, но все же.
А число экземпляров для диалога в Менеджере визуализации какое выставлено?Цитата:
Тем более, что в настройках визуализации стоит макс. число соединений - 100.
Вложение 56039
Да, но у меня же
VAR MyCloseDialog: VU.FbCloseDialog;
MyCloseDialog(itfClientFilter:=VU.Globals.AllClien ts, xExecute:=FALSE, sDialogName:=MyVisuName);
MyCloseDialog(itfClientFilter:=VU.Globals.AllClien ts, xExecute:=TRUE, sDialogName:=MyVisuName);
MyOpenDialog(itfClientFilter:=VU.Globals.AllClient s, xExecute:=FALSE, sDialogName:=MyVisuName, xModal:=TRUE);
MyOpenDialog(itfClientFilter:=VU.Globals.AllClient s, xExecute:=TRUE, sDialogName:=MyVisuName, xModal:=TRUE);
Понял, спасибо.
Интересно, чисто в теории CODESYS Group предоставляет информацию о методике разработки визуальных компонентов для WEB-визуализации? Партнеры компании, например, могут разрабатывать свои компонеты? Желательно с перемещением элементов внутри компонента мышкой. В другой системе я использовал парадигму на основе готового виджета-коммутатора, где источники сигнала (пиктограммы) перемещались на прямоугольные области с подписями, обозначающие дисплеи. Очень удобно. Там это правда было сделано на устаревшем Flash, но выглядело и работало супер.
В данный момент свои элементы можно разрабатывать с помощью платного плагина Visual Element Toolkit.
По вопросам приобретения можете написать на info@prolog-plc.ru
В CODESYS V3.5 SP18 анонсирована поддержна интеграции HTML5-контролов в web-визуализацию.
Потрясающе... будем смотреть. А скажите пожалуйста, детали может пока и не важны, модель WEB визуализации позволяет перебрать все контролы, определить их типы и индивидуальные имена, что бы потом в программе я смог автоматически обрабатывать события от них и для них? Сейчас я в каждый контрол занес несколько строк кода - индекс, флаг нажатия. В принципе - работает. Но ведь можно пойти и дальше, просто разработав для себя определенные правила по наименованию контролов.
Добрый день!
Скажите, а никто не наблюдал такую штуку. Есть текущий экран в визуализации. На него поступают короткие символьные данные (примерно 16 строк в элементы Текстовое поле, в каждое поле около 10 символов), а также преключаются состояние кнопок (цвет обычный или тревога) в зависимости от состояния системы. Цвет кнопок переключается не сказать чтоб интенсивно, примерно 4 изменения в секунду, скажем так. Всего кнопок 40 штук. Да и строки меняются раз в несколько секунд, но зато все сразу, одна за другой. Потом по строкам опять пауза, меняется только состояние кнопок.
При переходе из программы, через менеджер визуализации, на другой экран, это происходит не всегда. Примерно в 10-20% случаев экран может не измениться на нужный. Повторная операция как правило помогает. Есть подозрение, что это зависит от того, насколько сильно в момент переключения занят текущий "визуализатор". Во всяком случае, когда на экраны выводилось меньше информации, смена активных экранов происходила без проблем.
P.S. Да нет, похоже я был не прав. Снял всю нагрузку с визуализации, оставил только переключение экранов. Все равно иногда не переключается, хотя на текущем экране ничего не обновляется. Переменные привязаны к визуальным компонентам, но они, переменные, не обновляются в программе, соотв. строки закоментированны.
Видимо, одно из двух - или переменные все время опрашиваются, такой вариант тоже может быть. В конечном итоге нужно ведь как-то события их изменения фиксировать. Или вот эта конструкция для смены экранов:
MySetVisu(itfClientFilter:=VU.Globals.AllClients, xExecute:=FALSE, sVisuName:=MyVisuName); // Взбадриваем подсистему
MySetVisu(itfClientFilter:=VU.Globals.AllClients, xExecute:=TRUE, sVisuName:=MyVisuName); // По переднему фронту отображаем нужный экран по имени визуализации
обладает каким-то принципиальным недостатком. И еще - когда не ждешь, этот дефект проявляется. Начинаешь его ловить при прочих равных - щелкаешь, щелкаешь - и ничего. Я уж тут думал - не JS ли в браузе тормозит иногда? Но сомнительно, сомнительно. Хотя, у всех наверное, бывали ситуации, когда для отправки формы в браузере приходилось нажимать кнопку еще раз. Но, наверное, это было бы слишком просто.
Добрый день!
Вдогонку. Понял, что установка "Использовать переменную CurrentVisu" решает проблему автоматической синхронизации начальных экранов при подключении нового WEB-клиента без всякого дополнительного кода (это я как-то просмотрел ранее). Но, к сожалению, это не распространяется на открытые диалоги. Интересно, если диалоги заменить на фреймы - будут ли они отображаться автоматически, а не как с диалогами, которые приходится открывать из программы? И будет ли фрейм, если он не на весь экран, модальным как диалог?