QtDesigner/NGL Widgets
Итак хотелось бы рассмотреть виджеты которые доступны в python пакете ngl-utils и как с ними работать. Давайте посмотрим, запустим скрипт ngldes из пакета ngl-utils набрав в консоли
> ngldes
После запуска QtDesigner видим следующие виджеты:
- NGL_Button
- NGL_Bitmap
- NGL_CheckBox
- NGL_FillBar
- NGL_GraphScale
- NGL_Label
- NGL_Line
- NGL_Rect
- NGL_SeekBar
NGL_Button
В браузере свойств объекта видим 3 категории разделенные по родителям виджета - QObject, QWidget, NGL_Base, и непосредственно уникальные свойства NGL_Button. В QObject у нас только имя объекта, в QWidget координаты, размер, таблица стиля и т.п. Таблица стилей для NGL_Button определяет цвет фона кнопки и цвет текста, значение по умолчанию:
background-color: rgb(192, 0, 0);
color: rgb(64, 64, 64);
В группе NGL_Base находятся общие свойства для всех виджетов NGL, свойство layer сейчас на стадии альфа, поэтому не обращаем на него внимания и не трогаем пока. Объекты будут отрисовыватся в порядке установленном в QtDesigner, то есть объекты добавленные на форму ранее будут слоем ниже добавленных позже, также нужно учесть что статические объекты будут отрисованны всегда ранее "динамических", порядок в каждой группе объектов определяется так как указано ранее. Свойсвто eventsEnabled определяет будет ли сгенерированно событие нажатия или другой активации виджета, если да то для объекта будет сгенерированна функция обработчик события в файле страницы к которой принадлежит объект, например:
static void btnControls_click(void)
{
}
Также в объявлении структуры объекта будет проставлен указатель на эту функцию, связывающий объект и обработчик. Если же eventsEnabled выключено, то обработчик не будет сгенерирован, а в объекте указатель на обработчик будет равен указателю на ноль - (void*)0. Свойство clickEventName отвечает за имя функции обработчика события, таким образом можно связать несколько объектов с одним событием.
Теперь рассмотрим группу свойств NGL_Button, уникальных для виджета NGL_Button. styleType, бывает 4 типов:
- text -- просто текст
- fill -- обычная, залитая фоном, прямоугольная кнопка
- ico -- кнопка иконка, больше ничего
- ico_text -- иконка плюс текст
На скриншоте выше кнопка имеет тип fill, пример NGL_Button типа ico_text можно посмотреть здесь.
Свойство font отвечает за используемый шрифт, text - текст кнопки, text_sx/text_sy - эксперементальные, можно не обращать внимания. gradient отвечает за то как будет залита кнопка в режиме fill, если включено, то кнопка будет залита от цвета указанного в таблице стилей, до более светлого того же оттенка, если выключено, то кнопка будет просто залита одним цветом. icon - иконка кнопки, имеет значение только если кнопка типа ico или ico_text, iconSize - отвечает за размер иконки.
Структура кнопки в NGL:
/* NGL UI Button type */
typedef struct {
const uint16_t X; // Left X coordinate
const uint16_t Y; // Down Y coordinate
const uint16_t Width; // Button width (X1 = X0 + Width)
const uint16_t Height; // Button height (Y1 = Y0 + height)
const NGL_ButtonType Type; // Type of button
uint16_t Color; // Forecolor for "Fill" type
uint16_t SelectedColor; // Forecolor selected button for "Fill" type
const FunctionalState ColorShift; // Forecolor shift for "Fill" type
const NGL_Image *ICO; // Icon/bitmap
const NGL_Font *Font; // Font for text
const int16_t TextOffset_X; // Text X offset
const int16_t TextOffset_Y; // Text Y offset
uint16_t TextColor; // Color for text
char* Text; // Text
const NGL_ReClickState ReClickState; // Enable or disable repeated clicks events
FunctionalState Visible; // Visible state
FlagStatus Enabled; // Enabled state, if RESET button not active and not request all clicks events
const pEvent ClickEvent; // Click event function pointer
} NGL_Button;
NGL_Bitmap
Это совсем простой виджет, кроме базовых свойств QObject/QWidget/NGL_Base у данного виджета есть только свойство ico - файл или ресурс изображения. Структура в NGL:
/* NGL Image type */
typedef struct {
const uint16_t Width; // Picture Width
const uint16_t Height; // Picture Height
const uint8_t Compressed; // Copressed flag, 0 - NonCompressed, 1- RLE, 2 - picoJPG
const uint8_t ColorBits; // color bit per pixel
const uint8_t DataBits; // bitmap data array value bits
const uint32_t DataArraySize; // Last index of bitmap data array
const void *Data; // data pointer
} NGL_Image;
NGL_СheckBox
Свойство checked отвечает за начально состояние checkbox-а, boxcolor - цвет прямоугольной области, цвет шрифта задается в таблице стилей, например на скриншоте задано - color: rgb(128, 0, 128);. text и font задают текст, и каким шрифтом он будет отрисован. Структура в NGL:
/* NGL UI CheckBox type */
typedef struct {
const uint16_t X0, Y0, X1, Y1;
FunctionalState Checked;
const NGL_Font* Font;
const char* Text;
uint16_t Color;
uint16_t TextColor;
const pEvent ClickEvent;
} NGL_CheckBox;
NGL_FillBar
NGL_FillBar может быть использован как индикация прогресса того или иного выполняемого действия, или для индикации значения различных параметров, например напряжения, давления, и т.п. Свойство level - уровень в относительных еденицах, не может быть больше максимума - maximum, и меньше минимума - minimum, то есть если level - 50, minimum - 0, maximum - 100, то виджет будет залит до своей геометрической середины по X или Y, в зависимости от ориентации, которая задается свойством orientation, и может принимать два значения - Horizontal / Vertical. logaritmic - логарифмическая шкала заливки, при тех же условиях (lvl - 50, min - 0, max - 100) "уровень" заливки будет расчитан по формуле (пример для горизонтального fillbar):
Level_dB = fullscale_dB - 20*log10( ( maximum - minimum ) / level )
fiil_width = level_dB * ( ( X1 - X0 ) / fullscale_dB )
Выделенный, на скриншоте, виджет NGL_FillBar, как раз имеет тип logaritmic, остальные свойства также схожи с приведеным примером. Если свойство logaritmic выключено, то уровень заливки будет линеен между максимумом и минимумом. fullscale_dB - имеет значение только если у виджета установлено свойство logaritmic в true, задает полную шкалу в дБ. orientation - Horizontal / Vertical, горизонтальная или вертикальная ориентация, border - отрисовывать ли прямоугольник вокруг границ виджета или нет. markers / markers_color - "маркеры" в начале и в конце шкалы, их цвет. Структура в NGL:
/* NGL UI FillBar type */
typedef struct {
const uint16_t X0, Y0, X1, Y1;
const NGL_VertHoriz_Type Orientation;
const uint16_t Level_MIN, Level_MAX;
uint16_t Level;
uint16_t sfX1, sfY1;
FunctionalState Logarithmic;
uint16_t FullScale_dB;
FunctionalState Border;
FunctionalState Markers;
uint16_t MarkersColor;
uint16_t Color;
} NGL_FillBar;
NGL_GraphScale
Может использоватся как шкала к NGL_Fillbar или например к графикам, на приведенном скриншоте вверхний горизонтальный NGL_GraphScale имеет шкалу 0 - 25 А , у красного NGL_Fillbar сразу под ним установлено - minimum = 0, maximum = 25, level = 15, как видим все совпадает со шкалой. У второй "группы" NGL_GraphScale / NGL_Fillbar шкала в дБ, и у NGL_Fillbar установлено - minimum = 0, maximum = 100, level = 25, logarithmic = true, fullscale_dB = 90, все опять совпадает.
font - шрифт меток шкалы, gradientText - эксперементальная, пока игнорируется, maximum / minimum / scale_cent - отвечают за максимальное/минимальное значения шкалы и цену деления, labels - метки шкалы, задаются строкой через запятые, принимаются только числовые значения. units - еденица измерения шкалы. showLabels / showLines - отрисовывать или нет метки / шкалу.
orientation / flip - горизонтальная или вертикальная ориентация, инвертирование вокруг "оси". Структура в NGL:
/* NGL UI GraphScale type */
typedef struct {
const uint16_t X0, Y0, X1, Y1;
int MIN, MAX;
int Cent;
const int Labels[20];
uint8_t LabelsCount;
char *Units;
FunctionalState ShowLabels;
FunctionalState ShowLines;
FunctionalState Flip;
const NGL_VertHoriz_Type Orientation;
NGL_Font* Font;
uint16_t Color;
} NGL_GraphScale;
NGL_Label
NGL_Label имеет всего 3 уникальных свойств, font / text - шрифт и текст метки, static отвечает за то каким образом метка будет "представлена" на странице, если параметр установлен в true, то метка будет отрисована один раз при отрисовке страницы, в групе статических объектов, иначе будет сгенерирована структура NGL_Label и указатель на нее добавлен в структуру страницы, таким образом становится возможным легко отрисовывать и главное - обновлять метку, для этого служат функции:
void NGL_GUI_DrawLabel(const NGL_Label *Label);
void NGL_GUI_UpdateLabel(const NGL_Label *Label, char *NewText);
Обновляется только изменившийся текст, это дает минимум мерцаний и большую скорость, но это же привносит недостаток - при необходимости обновить метку, без изменения текста, другим цветом, функция NGL_GUI_UpdateLabel не сделает ничего. В этих случаях, в качестве исключения, необходимо вызвать полную отрисовку метки - NGL_GUI_DrawLabel. В общем намного экономичней по ресурсам использовать статические метки, если не предполагается изменения их текста, и/или отдельной от общей перересовки. Структура в NGL:
/* NGL Label type */
typedef struct {
const uint16_t X; // Left X coordinate
const uint16_t Y; // Down Y coordinate
uint16_t Color; // Text color
const NGL_TransparentState Transparent; // Transparent state
char* Text; // Text
const NGL_Font *Font; // Label font
} NGL_Label;
NGL_Line
Координаты NGL_Line определяют свойства Geometry его родителя QWidget и собственные координаты начала и конца отрезка, эти координаты задаются "внутри" прямоугольной области определенной Geometry, с началом координат в 0, 0.
NGL_Rect
Тут совсем все просто, геометрия прямоугольника определяется в Geometry, свойсвто fill - закрашен или нет.
NGL_SeekBar
Предназначен для изменения каких либо параметров, генерирует событие нажатия, level / minimum / maximum определяют значение переменной level объекта в зависимости от положения ползунка. orientation - горизонтальная или вертикальная ориентация, show_progress - более светлая отрисовка от нуля до ползунка если включено. slidersize / slidercolor - размер и цвет ползунка. Структура в NGL:
/* NGL UI SeekBar type */
typedef struct {
const uint16_t X0, Y0, X1, Y1;
const uint16_t SliderSize;
uint16_t old_posX, old_posY;
const NGL_VertHoriz_Type Orientation;
const int16_t Level_MIN, Level_MAX;
int16_t Level;
FunctionalState ShowProgress;
uint16_t Color;
uint16_t SliderColor;
const pEvent ClickEvent;
} NGL_SeekBar;
Это все виджеты доступные сейчас в пакете ngl-utils, их вполне достаточно для разнообразных простых и компактных по ресурсам интерфейсов. Открытый исходный код библиотеки и ngl-utils, а также инструментов Qt, дает широкие возможности для кастомизации, расширения и любой другой модификации библиотеки, или инструментария.
NGL_Greed
На момент написания пакет ngl-utils не содержит такого плагина, предлагаю взять его в качестве примера создания своего виджета, я выбрал "сетку" потому что это достаточно показательный и простой объект, но заодно и полезный, может пригодится для тех же графиков/осциллограмм. Итак, если еще небыли скачаны исходники ngl-utils, то необходимо сделать это - репозиторий. Смотрим в папку nplugins видим две интересующие нас папки - python и widgets, в python лежат файлы "интерфейсов" виджетов к QtDesigner-у, в них описывается имя, иконка и т.п. Для каждого виджета должен быть соответсвующий файл "интерфейса" в котором объявлен класс плагина наследующий NGL_BasePlugin, который в сою очередь наследует QPyDesignerCustomWidgetPlugin. В папке widgets находятся сами виджеты которые могут использоватся как и обычные виджеты PyQt, то есть перед проверкой в QtDesigner их можно добавлять в свои приложения и проверить, или запускать как отдельное окно только с этим виджетом, по мере написания виджета "сетки" мы этим воспользуемся.
Создаем файл ngl_greed.py, в нем пишем следующее.
Сетка будет иметь 4 своих свойства - отрисовка центральных линий и их цвет, размер ячейки по X и по Y. Для каждого свойства должен быть объявлен setter/getter для того что QtDesigner "подхватил" его и вывел в браузере свойств объекта. setter/getter для переменной типа bool будет выглядеть подобным образом:
@pyqtProperty(bool)
def central_lines(self):
return self._central_lines
@central_lines.setter
def central_lines(self, state):
self._central_lines = state
self.update()
Сразу и проверим! В SublimeText просто нажиамем F7, или в консоли набираем - python ngl_greed_plugin.py
Как видим все предельно просто, и все работает, но центральные линии привязаны к геометрическому центру виджета, а сетка к началу координат. Из-за этого как видно есть как на скриншоте, для устранения этого "недостатка" нужно привязать сетку также к геометрическому центру виджета, смотрим модифицированный вариант.
Проверяем...
Отлично, теперь создадим "интерфейсный" файл ngl_greed_plugin.py и объявим в нем класс NGL_GreedPlugin - результат.
Все готово к проверке в самом QtDesigner, сохраняем оба файла в соответсвующие папки - python / widgets, и запускаем скрипт setup.py, из корневой папки скаченного пакета ngl-utils.
> python setup.py install
Запускаем Qtdesigner скриптом ngldes:
Остается только написать метод генерации кода под наш виджет, для этого создадим в папке templates текстовый файл с расширением ntp - greed.ntp с следующим содержимым:
/* {pageName} {itemName} item */
NGL_Greed {itemName} = {{
{x},
{y},
{width},
{height},
{central_lines},
{central_lines_color},
{cell_widht},
{cell_height},
{color}
}};
Это, как наверно уже понятно, просто шаблон, последнее - модифицируем файл ngl_greed.py - окончательный результат.
Еще раз собираем пакет, для того что бы внесенные изменения "отразились" на всех связаных компонентах пакета:
> python setup.py install
теперь можно запускать ngluic, предварительно создав и сохранив файл greed_test.ui, с добавленным на форму виджетом NGL_Greed, кому лень - вот готовый.
> ngluic -u greed_test.ui --verbose
На выходе - страница,
объявление структуры NGL_Greed
весь сгенерированный код одним архивом.
Практически можно пользоватся (:, так как пока сама библиотека NGL ничего не знает о структуре типа NGL_Greed, но об этом чуть позже...
print( [ln.format() + '\n' for ln in links] )
|
|