Qt предоставляет программисту очень богатые возможности, однако набор виджетов ограничен. Если ничего из имеющегося в наличии не подходит, приходится рисовать что-то свое. Простейший способ — использовать готовые картинки — имеет серьезные недостатки: необходимость хранения изображений в файле или ресурсах, проблемы с масштабируемостью, с переносимостью форматов изображений. Ниже описывается вариант использования принципов векторной графики без использования собственно векторных изображений. Началось все с того, что понадобилась однажды индикация одноразрядных признаков. Некоторое приложение получает по некоторому порту некоторые данные, пакет надо разобрать и отобразить на экране. Хорошо бы при этом как-то имитировать привычную приборную лицевую панель. Для отображения цифровых данных Qt предлагает «из коробки» класс QLCDNumber, похожий на знакомые семисегментные индикаторы, а вот одиночных лампочек что-то не видно. Использование флажков (они же check boxes) и переключателей (они же radio buttons) для этих целей плохо, и вот список причин: Вывод: надо рисовать лампочку самому. Сначала поискал готовые решения. В ту далекую пору, когда использовал Delphi, можно было найти просто гигантское количество готовых компонентов, как от серьезных фирм, так и любительского изготовления. В Qt с этим напряженка. У QWT есть кое-какие элементы, но не то. Любительщины вообще не видел. Наверное, если грамотно рыть на Github`е, то можно что-то найти, но я, пожалуй, быстрее сам сделаю. Первое, что напрашивалось из самодельного — использовать два файла-картинки с изображениями включенной и выключенной лампочки. Плохо: Второе, что вытекает из первого — вместо картинок использовать векторные изображения. Тем более, что Qt умеет рендерить SVG. Тут уже чуть проще с поиском собственно изображения: в сети много уроков по векторной графике, можно найти что-то более-менее подходящее и адаптировать под свои нужды. Но остается вопрос по хранению и настраиваемости, да и рендеринг не бесплатен по ресурсам. Копейки, конечно, но все же... И третье вытекает из второго: можно же воспользоваться принципами векторной графики при самостоятельной прорисовке изображения! Файл векторной картинки в текстовом виде указывает, что и как рисовать. Я могу кодом указать то же самое, используя векторные туториалы. Благо, у объекта QPainter имеются в наличии необходимые инструменты: перо, кисть, градиент и рисование примитивов, даже заливка текстурой. Да, инструменты далеко не все: нет масок, режимов наложения, но совсем уж фотореалистичности не требуется. Поискал немного примеры в сети. Взял первый попавшийся урок: «Рисуем кнопку в графическом редакторе Inkscape» с сайта «Рисовать легко». Кнопка из этого урока гораздо больше похожа на лампочку, чем на кнопку, что меня вполне устраивает. Делаю заготовку: вместо Inkscape — проект в Qt. Создаю новый проект. Выбираю название проекта rgbled (потому что хочу сделать что-то вроде RGB-светодиода) и путь к нему. Выбираю базовый класс QWidget и название RgbLed, отказываюсь создавать файл формы. Проект по умолчанию после запуска делает пустое окно, оно пока неинтересное. Заготовка есть. Теперь надо завести закрытые члены класса, которые будут определять геометрию рисунка. Существенным плюсом векторной графики является ее масштабируемость, поэтому константных чисел должно быть по минимуму, и те лишь задавать пропорции. Размеры будут пересчитываться в событии resizeEvent(), которое надо будет переопределить. В используемом уроке по рисованию размеры задаются в пикселах по ходу действия. Мне же нужно заранее определить, что я буду использовать и как пересчитывать. Рисуемая картинка состоит из таких элементов: Концентрические круги, то есть, всё, кроме бликов, определяется позицией центра и радиусом. Блики определяются центром, шириной и высотой, причем позиция X центров бликов совпадает с позицией X центра всего рисунка. Для расчетов элементов геометрии понадобится определить, что больше — ширина или высота, потому что лампочка круглая и должна вписываться в квадрат со стороной, равной меньшему из двух измерений. Итак, добавляю соответствующие закрытые члены в заголовочный файл. Затем переопределяю защищенную функцию, вызываемую при изменении размеров виджета. Здесь вычисляется сторона квадрата, в который вписана лампочка, центр этого квадрата, радиус ободка, занимающего максимально возможную площадь, ширина ободка, внешняя часть которого пусть будет 1/10 от диаметра, а внутренняя — 1/14. Затем вычисляется положение бликов, которые находятся в серединах верхнего и нижнего радиусов, ширина и высота подбираются на глазок. Кроме того, в защищенные поля сразу добавлю набор цветов, которые будут использоваться. По названиям примерно понятно, что это цвета лампочки, светлой части тени, темной части тени, три цвета кольцевой тени вокруг лампочки и цвета градиентов бликов. Цвета надо бы инициализировать, поэтому дополню заготовку конструктора. Еще надо не забыть вставить в заголовочный файл инклуды классов, которые понадобятся при рисовании. Этот код компилируется успешно, но в окне виджета ничего не изменилось. Пора начинать рисовать. Ввожу закрытую функцию и переопределяю защищенную функцию Событие перерисовки будет вызывать собственно рисование, которому в качестве параметра передается цвет «стекла». Пока так. А функцию рисования начинаем понемногу заполнять. Сперва создается объект-художник, который и будет заниматься рисованием. Затем создается карандаш, который нужен для того, чтобы карандаша не было: в данном изображении обводка по контуру не просто не нужна, а вообще не нужна. Затем рисуется первый круг в примерном соответствии с уроком по векторной графике: большой круг, залитый радиальным градиентом. У градиента светлая опорная точка вверху, но не на самом краю, а темная — внизу, но тоже не на самом краю. На основе градиента создается кисть, этой кистью художник painter закрашивает круг (то есть, эллипс, вписанный в квадрат). Получается такой код Среда подчеркивает параметр color функции drawLed, потому что он не используется. Пусть потерпит, он пока не нужен, но скоро понадобится. Запущенный проект выдает такой результат:  Добавляем еще порцию кода. Почти тот же самый круг, только меньше размером и вверх ногами. Получаем такую картинку:  Дальше наконец-то понадобится цвет стекла: Здесь при помощи функции darker из переданного цвета получается такой же цвет, но потемнее, для организации градиента. Коэффициент 120 подобран на глазок. Вот результат:  Добавляю кольцевую тень вокруг стекла. Так сделано в уроке по векторной графике, и это должно добавить объему и реалистичности: Тут градиент трехступенчатый, чтобы тень была гуще к краю и бледнела к центру. Получается так:  Добавляю блики, сразу оба. Верхний блик в отличие от нижнего (и всех остальных элементов) сделан линейным градиентом. Художник из меня так себе, поверю на слово автору урока. Возможно, в этом есть какая-то правда, экспериментировать с разными видами градиентов не буду. Вот, собственно, и все, готовая лампочка, как на КДПВ.  На заметность бликов и выпуклости стекла влияет цвет, точнее, то, насколько он темный. Возможно, имеет смысл добавить регулировку яркости бликов и коэффициента затемнения в функции darker в зависимости от темности, но это уже перфекционизм, я считаю. Ниже — пример использования в окне программы.  Для интереса можно поиграться с цветами. Например, переопределив защищенное событие клацанья мыши таким образом: не забыв добавить мышиные события в заголовок: Теперь щелчок мыши по компоненту будет переключать цвет лампочки: красный, зеленый, синий, серый и какой-то от фонаря наугад подобранный. Что касается рисования, то на этом все. А виджету следует добавить функциональности. В моем случае было добавлено булево поле «использовать ли состояние»", еще одно булево поле, определяющее состояние «Вкл» или «Выкл» и цвета по умолчанию для этих состояний, а также открытые геттеры и сеттеры для всего этого. Эти поля используются в функции paintEvent() для выбора цвета, передаваемого drawLed() в виде параметра. В результате можно отключить использование состояний и задавать «лампочке» любой цвет, а можно включить состояния и зажигать или гасить лампочку по событиям. Особенно удобно сделать сеттер состояния открытым слотом и соединить его с сигналом, который надо отслеживать. Использование mousePressEvent демонстрирует, что виджет можно сделать не только индикатором, но и кнопкой, делая ее нажатой, отпущенной, гнутой, скрученной, раскрашенной и какой хотите еще по событиям наведения, нажатия и отпускания. Но это уже не принципиально. Целью было показать, где можно взять образцы для подражания при прорисовке собственных виджетов и как эту прорисовку несложно реализовать без использования картинок растровых или векторных, в ресурсах или файлах. инженер-программист