Создание системы расширения на библиотеке Qt — Часть 2

    Возвращаясь к первой статье хочется объяснить откуда появилась необходимость разработки механизма расширения с графическим интерфейсом (GUI) и подробней объяснить механизм создания плагинов.

    Было получено задание на разработку технологического программного обеспечения для настройки, регулирования, контроля, сбора и анализа информации САУ(системы автоматизированного управления) двигателя, на российской операционной системе. Где обмен между САУ и технологической программой осуществляется по интерфейсу RS-232 или RS422, по специальному протоколу обмена.

    После рассмотрения и анализа возможностей списка российских операционных систем была выбрана операционная система AstraLinux. Это система специального назначения на базе дистрибутива Debian, созданная для комплексной защиты информации и построения защищённых автоматизированных систем. Операционная система Астра Линукс разрабатывается в двух модификациях: Common Edition(бесплатная, общего назначения) и Special Edition(платная, специального назначения с пакетом алгоритмов защиты).
    При разработке программного обеспечения была использована библиотека Qt.

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

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


    Функциональный модуль “Приборная панель”


    Функциональный модуль, позволяющий динамически контролировать значения параметров в допустимых границах


    Функциональный модуль для настройки характеристик САУ

    Разработанное ПО (технологическая программа) было предназначено только для определенного типа двигателя. Для нового типа двигателя приходилось разрабатывать новое ПО, что приводило к значительному увеличению трудозатрат на разработку, тестирование, отладку и, как следствие, задержкам на внедрение данного ПО — при том, что, подобное ПО востребовано уже на этапе разработки САУ.

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

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

    Программный комплекс состоит из трех основных частей:

    1. Функциональное ядро комплекса
    2. Механизм системы расширений
    3. Набор плагинов

    В функции ядра входит обеспечение надежного обмен данными с САУ и выполнение следующих задач:

    • Обмен информацией по интерфейсу RS232 с использованием специального протокола
    • Непрерывный мониторинг списка параметров двигателя
    • Запрос на изменение параметров двигателя
    • Запросы на чтения параметров двигателя
    • Отображение параметров виде табличной формы
    • Обработка запросов от расширений(создания нового списка мониторинга по необходимости, одиночные запросы на запись и считывание)

    Система расширения со следующими функциями:

    • Поиск расширений
    • Получение графических объектов расширений
    • Отображение объектов расширений
    • Задача по связыванию запросов(сигналов) от объектов к ядру ПО

    Каждый плагин является фабрикой объектов, и основной функцией плагина является создание графического объекта.

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

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



    Разработка иерархия плагина.



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

    Следующим классом является QWidget — он необходим для создания своих графических форм.

    Далее необходим свой класс интерфейсов interfaceWidget. Для этого создаётся абстрактный класс, который будет наследоваться от QWidget. В этом классе объявляются интерфейсы (сигналы, функции, слоты) которые будут связывать основной проект и объект плагина. Абстрактный класс обеспечивает поддержку интерфейса в основном проекте.

    Класс MyFormQt, который наследуется от класса интерфейсов interfaceWidget и определяет интерфейсы и и в котором разрабатывается графика и внутренняя функциональность модуля. Благодаря такой схеме наследования класс MyFormQt, поддерживает функционал класса QWidget и разработанные интерфейсы связи с основным объектом приложения.

    /**
       \class interfaceWidget
       \brief Виртуальный класс,объявляющий интерфейсные функции  графического функционального объекта
    */
    class interfaceWidget: public QWidget
    {
    public:
            /// \brief Деструктор
            virtual ~interfaceWidget() = default;
            /// \brief Функция получения байт
            /// \param ba, полученные байт из САУ
            /// \param ok, флаг успешного считывания
            virtual void getByte(QByteArray ba, bool ok) = 0;
            /// \brief Функция получения циклических данных
            /// \param ba, полученные байт из САУ
            virtual void getRetrieveDate(QByteArray ba, bool ok) = 0;
            /// \brief Функция успешной записи данных
            /// \param fl, флаг записи
            virtual void successfullyWritten(bool fl) = 0;
            /// \brief Фунуция для запроса регистрации параметров
            /// \param ok Флаг необходимости регистрации параметролв
            /// \return параметрцы которые необходимо зарегистрировать в потоке мониторинга
            virtual QVector<QString > regParam(bool &ok) = 0;
    signals:
         
            /// \brief сигнал запроса записи данных в САУ
            /// \param Вектор название параметров и их значений
            virtual void  signal_writeByteByName(QVector<TVARPARAM > vecParam) = 0;
            /// \brief Сигнал запроса данных по имени
            /// \param nameParam вектор параметров
            virtual void signal_getByteByName(QVector<QString > nameParam) = 0;
            /// \brief Сигнал запроса данных по адрессу
            /// \param addr адресс откуда надо начать считывать данные
            /// \param ndata кол-во байт для считывания
            virtual void signal_getByteByAddress(quint32 addr, quint32 ndata) = 0;
            /// \brief Сигнал запроса записи данных по адрессу
            /// \param addr адресс куда надо записать данные
            /// \param ba байты для записи
            virtual void signal_writeByteByAddress(quint32 addr, QByteArray ba) = 0;
            /// \brief Сигнал запроса на остановку мониторинга
            /// \param fl, true старт мониторинга, false стоп мониторинг
            virtual void signal_enableMonitoring(bool fl) = 0;
    };
    

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

    Процесс инициализации и обмена данными.Весь проект основан на MDI области следственно все плагины будут загружаться в виде отдельного MDI окна.

    Плагин-фабрика создает объект класса MyFormQt, преобразует указатель на созданный объект к указателю на QObject и передает его в технологическую программу, где следует преобразование объекта c помощью операции dynamic_cast на объекта класса interfaceWidget, в следствии чего получаем полный доступ к графической форме и интерфейсам этого объекта.

    Функция фабрики (создание графического функционального объекта в плагине).

    //------------------------------------------------------------------
    QObject *screenOnlinePlugin::getPluginWidget()
    {
       MyFormQt *screen = new MyFormQt();
       return qobject_cast<QObject *>(screen); // Преобразование в объект
    }
    //-------------------------------------------
    

    Функция получения и инициации графического функционального объекта в технологической программе (ядро).

    //-----------------------------------------------------------------
    void PluginSystem::showPluginWidget(QString dirFabrica)
    {	
       QMdiSubWindow *sWPS = new QMdiSubWindow;
       pQtTM->m_pma->addSubWindow(sWPS);
       sWPS->setAttribute(Qt::WA_DeleteOnClose, true);
      //--------Создание плагина
        QPluginLoader loader(dirFabrica);	   // Загрузка фабрики 
        QObject *pobj = qobject_cast<QObject*>(loader.instance());
          if(!pobj)
            return;
        pluginInterface *fabrica = qobject_cast<pluginInterface *>(pobj);
           if(!fabric)
             return;
        QObject *ob = fabrica→getPluginWidget();  // Получение графического объекта
           if(!ob)
             return;
     interfaceWidget *interFaceW = dynamic_cast<interfaceWidget *>(ob);
          if(!interFaceW)
            return;
     delete fabrica;
    
      //  Инициализация плагина 
      connect(interFaceW, SIGNAL(), this, SLOT());
    		
      sWPS->setWidget(interFaceW);
      sWPS->show();
        
      //  Регистрация параметров
      QVector<QString > vecParam;
      vecParam = interFaceW→regParam(paramOK); // Запрос параметров
      if(paramOK)
        regParamList(vecPlugin[i].namePlugin ,vecParam);
    }
    //--------------------------------------------------------------------------------
    

    Объект класса interfaceWidget (графический функциональный объект) помещается на созданное окно QmdiSubWindow, тем самым устанавливая его дочерним.

    Далее связываются(connect) сигналы и слоты объекта с сигналами и слотами ядра технологической программы и последним этапом показ окна методом show(). При закрытия окна QmdiSubWindow, также будет удален объект класса interfaceWidget, т. к. заранее для subWindow в котором помещен объект было установлено свойство DeleteOnClose.

    Обмен данными между графическими функциональными объектами и технологической программой проходит используя маршалинг данных и два режима:
    • Однократный режим (запрос-ответ);
    • Режим мониторинга, постоянно получаем данные с периодом, определяемым механизмом обмена данными с целевым устройством;

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

    При однократном режиме пользователь нажимая кнопку в графическом функциональном объекте (виджете) генерирует сигнал, содержащий список параметров, данные которых следует считать в целевом устройстве (САУ) и передать в графический функциональный объект. Механизм обмена данными в основной программе обрабатывает сигнал и начинает запрашивать у САУ данные по RS-232, получаемые данные пакуются в QbyteArray и отправляются с сигналом в графический объект. Объект обладает списком запрашиваемых параметров и, следовательно, знает их типы, распаковывает данные, которые содержаться в QbyteArray и отображает их виде графиков и таблиц и специализированных графических виджетов (стрелочные индикаторы, цифровые индикаторы, кнопки с подсветкой и т.д.).

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

    На данный момент проходит тестирование и одновременно разработка групп плагинов под разные задачи.

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

    Были разработаны программные модули-драйверы физического уровня для проводного интерфейса RS-232 и беспроводных WIFI и Bluetooth.

    На сегодняшний день программный комплекс работает в 2-х канальном режиме, т. е. может работать одновременно с 2 САУ (это было требование заказчика). К любому из 2-х каналов пользователем подключаются плагины функциональных модулей.

    При тестирование удалось одновременно запустить 12 плагинов которые успешно обрабатывались ядром. И даже 12 плагинов не являются пределом для данной системы. За счёт системы двойной буферизации Qt, время затрачиваемое на рисование плагинов уменьшается и предотвращает мерцания плагинов, поэтому при наращивания количества плагинов в дальнейшем основная нагрузка будет идти только на обмен данных по интерфейсу RS-232. Хотя практика показывает, что во время отладки, настройки, тестирования САУ двигателя достаточно 3-4 одновременно работающих плагина.

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

    Были разработаны 2 комплекта плагинов для разных типов двигателя.

    Подключая комплект плагинов для определенного типа САУ к программному комплексу получаем многофункциональную программу для настройки, наладки и тестирования этого типа САУ.



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

    Комментарии 39

      0
      А какой лицензией Qt вы пользуетесь?
        0

        Лицензия LGPL

        –1
        О, вспомнилась молодость, когда-то очень давно занимался похожими проектами :).
        Сейчас правда QWidget — устаревший подход. Посмотрите в сторону QML, он гораздо интереснее. У меня он «зашел» далеко не с первой попытки, но когда я пересилил привычки и освоился то в полной мере оценил его выдающиеся достоинства.
          +1
          Виджеты вполне удовлетворяют требованиям «под десктоп» и при необходимости достаточно легко кастомизуются/стилизуются и адаптируются под современный, простите, свистопердящий интерфейс. Никто из digia не нарекал их устаревшими.
          QML же больше для игр, мобилок и встраиваемых систем.
            0
            На QML разработка и поддержка сильно упрощаются. Что совсем неочевидно при чтении документации, но когда начинаешь работать — там очень натурально и легко получается хороший MVC. Нет, виджеты конечно тоже работают, по-прежнему удобны, и на них 90% старых разработчиков сидит. Но новые приложения на них имхо смысла нет делать. Не только для мобилок но и для самого что ни на есть классического десктопа. Тем более что за мобилками в том или ином виде будущеее да и новые вкусные технологии типа того же webgl streaming в виджетах не поддерживаются.
              0
              Зря вы так. Это просто консерватизм. Всё совсем наоборот. Плюс вы забываете, что там даже кастомные виджеты писать даже удобнее. ( на том же С++ кстати)
              +3
              Сделал 5 полноценных проектов в связки QML/Qt за последние лет 7. И в конце каждого проекта понимал, что лучше бы сделал на чистом Qt. Код для связки Qt и QML получается слишком большой. Быстро надоедает его писать.
                0
                Никто и не говорил что в MVC кода меньше чем в условном «монолите», особенно со спагетти-кодом. Но если это поддеживать и развивать дальше планируется то затраты на организацию быстро окупаются.
                  +1
                  затраты на организацию быстро окупаются

                  Мой опыт показывает об обратном. Постоянно упираться в «ой а на QML так делать не получится» при реализации специфичных штук. Затраты меньше только на код, относящийся к GUI, но приложение гуи кодом не ограничивается. Интеграция с нативной частью почти всегда уже сжирает все преимущества, когда у вас 30-50к строк на QML.
                    0
                    Qt весь построен вокруг сигналов и слотов (при правильной реализации, а не когда от QThread наследуются и переопределяют run() ). Все сигналы и слоты абсолютно прозрачно пробрасываются в QML. Где конкретно возникает проблема? Что конкретно нельзя делать на QML?
                      +1
                      Я не говорю что что-то совсем нельзя сделать на QML. Делаешь нативную часть, к ней обвязку, и тп. я про то что выгода очевидная от QML заканчивается довольно быстро. А потом этого монстра еще и поддерживать)
                        –1
                        По-моему все с точностью до наоборот :). На виджетах набросать прототип может быть быстрее, но QML заставляет написать код правильно, так что его в дальнейшем легко поддерживать.
                    +1
                    В том-то и дело, что сначала кажется, что кода мало. А потом он начинает плодится и занимать % 20 от всего проекта. Да, в начале проекта QML позволяет быстро сделать красивую картинку, но с ростом проекта выгода от него начинает уменьшаться. В результате начинаешь думать, что лучше бы потратил время на написание собственных контролов в Qt в начале проекта.
                      0
                      QML тоже нужно уметь готовить в том плане, что лучше на нем в начале написать некую продуманную библиотечку «своих» контролов (если не хватает стандартных — скажем, QQC), чем по-быстрому накидать лапшу из примитивов (на лапше из примитивов «красивая картинка» делается быстро, это да), а потом эту лапшу плодить. Ну или если видишь, что начинает плодиться лапша, лучше вовремя сделать рефакторинг, вынести дублирующийся код в местную библиотечку компонентов, продумать его интерфейс. QML тоже вполне модульный, этим можно и нужно пользоваться для уменьшения количества кода.
                        +1
                        QML идеально приспособлен для написания собственных контролов.
                        Я серьезно. Набросать на QML кастомный компонент легче чем сделать кастомный виджет. Я в своих проектах кучу кастомных контролов так сооружаю, даже если типовой контрол — всего лишь специальным образом оформленная кнопочка используемая в четырех местах. Делается-то это тривиально и быстро, поэтому не жалко потратить чуть-чуть времени чтобы убрать копипасту.
                          0
                          Набросать на QML кастомный компонент легче чем сделать кастомный виджет.

                          +1. Причем намнооого легче.
                            0
                            Полностью согласен. Писать легко, контролы получаются красивыми и быстрыми, минимум кода. Именно это и подкупает в начале проекта. Но связка Qt с QML в итоге занимает много кода и времени. Возможно если всю логику проекта перегнать на сторону QML (под JS) это будет большой проблемой. Но когда логика на C++, а на QML только интерфейс, то для меня это проблема.
                              0
                              Связка Qt с QML идет через сигналы и слоты, что, вообще говоря, и для чисто нативного кода является наиболее «Qt-style» способом общения между собой разных частей приложения. В чем проблема-то? Может я что-то упускаю?
                                0
                                Сигналы/слоты, это если у вас только клавиши. Как только появляются поля ввода, то начинаются свойства, с процедурами чтения/установки и т.д. А если нужно передавать список или таблицу, то программного кода получается очень много. В результате на каждую сущность нужно городить модель. И в конце проекта получается этих моделей штук 20-30, иногда больше.
                                  0

                                  Модели точно так же надо и для виджетов делать. Для тривиальных вариантов типа списка строк есть стандартные модели.

                                    0
                                    Имхо вы либо не правильно «варите» Qt, либо что-то не так делаете. Т.к. и в виджетах модели делать надо, делегаты делать надо и прочее. Это ключевой момент отделения UI от логики. Если приложение спроектировано нормально, то перевод на QML с виджетов — тривиальная задача… Да хоть в консоль, хоть вынести UI в веб. QtQuick к этому и приучает.
                                      +1
                                      Простой пример. Есть приложение. В приложении есть некоторые настройки. Эти настройки редактируются на отдельной форме. Требуемое поведение: после изменения настроек проверить их совместимость между собой и в случае отсутствия ошибок применить эти настройки для приложения (пока редактируются настройки, приложение работает на старых настройках). В случае ошибок совместимости настройки не применяются (к примеру, выдается сообщение об ошибках, и форма не закрывается). После изменения, настройки сохраняются, к примеру, в файл для восстановления при следующем запуске приложения.

                                      Как я это делаю на чистом Qt. Панель диалога, при инициализации собираются настройки и заполняются соответствующие контролы. При Accept'е формы данные с контролов читаются, проверяются, если все Ок, то данные записываются в текущие настройки приложения, вызывается метод записи текущих настроек в файл.

                                      Как я это делаю в связке Qt/QML. На Qt пишется модель настроек, причем в этом же классе появляются методы: чтение текущих настроек в модель, проверка настроек, применение настроек (запись в текущие настройки + запись в файл). Эта модель экспортируется в подсистему QML. Делается QML форма. В ней контролы bind'ятся на данные модели, в методе onComplete вызывается метод чтения текущих настроек в модель, на клавишу Ok вешается JavaScript код, который вызывает связку проверки и применения настроек.

                                      Итого: в связке Qt/QML появляется лишний класс модели, который по факту ничего не делает. А если настроек много, то кода получается тоже много (на каждое поле настроек по три метода).
                                        +1
                                        Почему лишняя то? У вас ошибка в проектировании видимо. В нормальной реализации настройками оперирует отдельный класс ( доступ к текущим настройкам, сохранение в файл, загрузка, применение настроек, проверка валидации при применении ). Это и есть ваша модель. Как ваши виджеты, так и QML форма обращается именно к этому классу. Это и есть модель настроек. Разве я не прав?
                                        Тем более к этому же классу можно через сигналы слоты подконнектить все элементы, требующие обновления при изменении той или иной настройки. Всё очень удобно.
                                          0
                                          Одно из условий — в процессе редактирования приложение использует старые настройки. В той схеме, что вы описали, нельзя будет bind'ить контролы на свойства модели, иначе в процессе редактирование настройки приложения будут меняться (после изменения состояния отдельного контрола). Поэтому и получается «лишний» класс.
                                            0
                                            Тривиально можно, просто два instance одного класса создайте и все. Один — текущие настройки, другой — настройки в процессе редактирования. С копированием одного в другое по accept. Если же ну очень хочется обойтись вместо модели некоей кашей парсящей содержимое диалога, то есть такой класс как QVariantMap. Он биндится на JS object (по сути — словарь), так что при желании можно все данные из формы писать в единственный объект и читать дальше этот объект как QVariantMap из плюсов.

                                            Или еще проще — пишем функцию setSettings(x,y,z,....), делаем ее Q_INVOKABLE и просто зовем эту функцию в button.onClick, собирая необходимые аргументы
                                              0
                                              Два экземпляра класса — проблема будет при присвоении, никто автоматически вызывать нотификацию об изменении полей не будет, писать руками — опять лишний код.

                                              Вариант с setParam иногда использовал, но тогда пропадает одна из основных фишек QML — bind'инг.
                                                0

                                                Оператор копирования написать и все. Там уже должны быть методы setX() кидающие нужные нотификации при их вызове, достаточно просто их позвать. Или сделать на весь класс настроек одну нотификацию settingsChanged вместо нескольких отдельных на каждый элемент класса. Вариантов масса.


                                                В варианте с setParam Вы так и так не используете преимущества биндинга, так что невелика потеря

                                              +1

                                              Не совсем. Биндинг делайте односторонним. Т.е. ты биндишь гую текущие настройки, а не обоюдный биндинг. Т.е. отображаешь то что считал с модели. Когда ты меняешь эти параматры в форме, то они не применяются, биндинг срывается т.к. ты присваиваешь значение именно в форме (гую), а по завершении редактирование применяешь эти настройки т.е. всовываешь в модель по кнопке "сохранить". И всего делов… причем там же идёт проверка валидности.

                          +2
                          Посмотрите в сторону QML, он гораздо интереснее.

                          Для поиграться может и поинтереснее, а для долгоиграющего проекта лучше начинать писать на виджетах. Все реализовать на QML нельзя, как только начинается интеграция нативного кода, сложность быстро растет.
                          Хотя да, какой-нибудь там автомат по продаже пирожков и газировки на QML делать самое то)
                            0
                            А что конкретно там растет и не может быть реализовано? Я пока с таким не сталкивался, поделитесь опытом. Нативный код абсолютно прозрачно доступен из QML через штатные сигналы и слоты.
                              0
                              Ну например… первое что вспомнил — подскажите, как в QML отобразить произвольный форматированный текст (пришедший с веба например), в качестве надписи? В частности, часть текста подсветить красным. Заранее фрагмент, разумеется неизвестен.
                              Я вот не нашел способа это сделать)
                                0
                                Берем QML, помещаем туда компонент Text
                                Берем QObject который отображает нативный функционал в QML, добавляем ему слот в который приложение будет помещать полученный из веба текст:
                                Q_PROPERTY(QString myText READ myText NOTIFY myTextChanged)

                                Биндим в QML его со свойством text нашего QML-объекта Text
                                Text {
                                    text: cppInterface.myText    
                                }

                                И вроде бы на этом всё :). Нам приходит из веба текст, нативный код говорит emit myTextChanged, QML запрашивает строку у нативного кода в геттере myText() и отображает ее. Поддерживаемое форматирование — HTML и CSS. Пример выделения одного слова красным цветом
                                Hello <span style="font-color:red">world</span> in HTML

                                Передаем подобную строку в text — она отобразится с выделением слова world красным цветом.
                                По-моему тут от виджетов каких-то принципиальных отличий нету
                                  –2
                                  Спасибо что так все подробно расписали, в этом не было необходимости :) Я знаю как прокидывать разное, речь как раз про ограниченность текста:
                                  отличие принципиальное одно — указанный вами пример не работает.
                                  Не будет он ничего подсвечивать красным. Только что перепроверил с Qt 5.11, ну вдруг меня память подвела и я что-то там не попробовал.
                                    +4
                                    Я конечно понимаю что вы высокого мнения о себе, но эти комментарии, вообще-то, не только вы читаете. Как сформулировали вопрос — такой и получили ответ.

                                    Не будет он ничего подсвечивать красным.

                                    Ну если тупо копипастить не включая голову то да, «Qt работать» не будет. Чтобы заработало надо в компоненте Text дописать

                                    textFormat: text.RichText

                                    и в HTML использовать не font-color а просто color:
                                    Hello <span style="color:red">world</span> in HTML

                                    Все естественно прекрасно работает. Пруф (Qt 5.12):



                                    Отдельно доставляет то что вы мне заявляли что «подробно расписывать не было необходимости». По всей видимости я как раз недостаточно подробно все для вас разжевал :).
                                      0
                                      Ладно, был неправ (интересно что с этим же вопросом на форуме Qt мне сказали что это работать не будет, видимо тоже не знали про RichText).
                                      Это лишь одно из препятствий, с которым пришлось столкнуться. Лично мое мнение — перспектив для десктопного применения технология QML не несёт.
                                        0

                                        Ну я бы сказал что не на форумах надо вопросы задавать а RTFM — в доках по всё это подробно написано, я же не их космоса о RichText узнал. Десять минут на чтение доков и эксперименты и все. В виджетах же ровно та же особенность, в QT работа с текстом и стилями унифицирована. Или фишка в том что виджеты больше народу использует и на форумах лагче найти совет?

                            0
                            Я не против QML, но пока что для разработки десктопных приложений виджеты, себя полностью оправдывают, не тенет переходить на QML. И для данной темы(плагины) всё таки виджеты подходят больше.
                            А в плане интереса то в QML больше заинтересовало возможность работы с 3D моделями и их интеграция из других IDE.
                              0

                              Для десктопа да, виджеты вполне норм. Но для мобильной и embedded разработки QML лучше. Я, когда QML только появился, тоже сначала с неохотой на него переползал, но потом разобрался, проникся и пользую с удовольствием.

                                +1
                                Для десктопа QML подходит точно так же хорошо. Просто надо проникнуться.
                                Для примера можно взглянуть на blog.qt.io/blog/2018/03/06/slate-basic-pixel-art-editor-built-qt-quick
                                Но и то, там можно было сделать еще куда более удобно.

                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                          Самое читаемое