Комментарии 48
Простите, а что в вашем понимании "шпаргалка"?
при программировании мы будем иметь дело с двумя горизонтально связанными иерархиями: иерархия виджетов и иерархия QLayout -ов.
И те, и другие - наследники QObject, стало быть, у них все идентично с точки зрения взаимоотношений "parent-child" и все идентично в плане кто на ком лежит и кто автоуничтожается если уничтожается родитель. Просто в layout`ы добавлены удобные автопересчеты координат и размеров. Так что, в каком смысле мы имеем дело с двумя иерархиями - тоже не понял. Так можно дойти и до горизонтальной иерархии кнопок QPushButton "A", QPushButton "B".
С толку сбивает множественное наследование?
- QWidget Class Inherits:QObject and QPaintDevice
- QLayout Class Inherits:QObject and QLayoutItem
ну, в QML в этом смысле чуть меньше "параллельности иерархий", там раскладки и кнопки прямо восходят к Item. И все же почему "такая иерархия не совсем корректна"?
И все же почему "такая иерархия не совсем корректна"?
ну да! точно, я как-то действительно выпустил из виду что у QObject-ов своя иерархия. Но виджету нужен парент виджет, что бы он выполнял свои функции визуального объекта в составном визуальном объекте, насколько я понимаю. Получается там не 2 а три связанных иерархии надо иметь ввиду.
Обджекту нужен парент обджект, чтобы было понятно, кто на ком лежит и кто за чье существование отвечает. А визуально ориентированные штуки уже опираются на эту информацию, чтобы знать, относительно кого использовать координаты и что с ними делать дальше. Лэйаутам не очень нужны виджетовские фишки, потому что они реально не рисуются. Виджетам не нужны лэйаутовские штуки, потому что они легче относятся к пересчетам координат на лету. Так что работа с координатами у них есть у обоих, но реализована несколько по-разному. Поэтому у них разные вторые корневые предки. Хотя координаты используются и у тех, и у других. Но главное здесь - родитель/дочерний, для этого у них есть общий КуОбджект. Так что реальная иерархия тут только одна, восходящая к обджекту, остальное лишь детали реализации некоторых штук, которые не влияют на взаимоотношения между элементами. Основное взаимоотношение здесь - parent/child, остальное от лукавого.
Лэйаутам не очень нужны виджетовские фишки, потому что они реально не рисуются.
кроме самого рисования лейауту нужно место получить под рисование своего контента, а тому кто владеет этим лейаутом (окну или вышестоящему лейауту) какая разница рисуется сам лейаут или чайлды из этого лейаута, для владельца это все равно размещаемый и русуемый объект, вот это меня маленько и запутало что он вроде не для рисования, но его внутри все равно рисуют.
Вернусь сюда еще. Лэйаут себя не рисует, и никого на себе лежащего не рисует. В коде объявляются разного рода визуальные элементы. В коде этих элементов нет команд для рисования, для вывода в видеопамять через прастиосспади прерывание INT 10h. На основании иерархии, выстроенной на отношениях parent/child, рисуется граф сцены, который будет отрисовываться рантайм-частью библиотеки Qt, без которой ваше творение не запустится
Попробую обрисовать очень грубо, общий принцип.
Объявили мы в коде две кнопки. Через что-то типа setWidget() добавили на форму. Тем самым (внутри этой setWidget) сделали форму их родителем, при этом кнопки добавились в список childs этой формы. (ну, допустим, не непосредственно на форму, а через посредничество лэйаута, но это неважно). Добавили еще один лэйаут, он стал чайлд для формы. Добавили на новый лэйаут две кнопки, они стали чайлд для него. Такая иерархия, основанная только на свойствах parent/child из QObject
Запустили код. Сцена будет отрисовывать этот граф: берем форму, рисуем заданным размером в заданном месте экрана, помним координаты. Берем список чайлдс этой формы (хорошо, корневого лэйаута в нашем случае), там три элемента. Поехали по порядку. Сперва кнопка, ищем правила ее отрисовки. В зависимости от лэйаута это могут быть координаты, берем их из свойств кнопки и рисуем относительно запомненных координат текущего родителя. Либо раскладкой управляет лэйаут, тогда свойства-координаты дочернего элемента игнорируем, а используем правила вычисления координат для дочерних элементов, взятые от текущего родителя (типа прижать влево, поэтому для первого дочернего х=0). Нарисовали саму кнопку - смотрим ее список дочерних элементов. Пусто - хорошо. Не пусто - смотрим, есть ли визуальные. Нарисовали одну кнопку, берем следующую. Координаты перекрываются почему-то? Если z-ордер одинаковый, тупо рисуем поверх. Берем следующий элемент из списка - это еще один лэйаут. Для начала расчитываем его координаты исходя из его родителя (лэйаута и его правил) и заданных уточнений в самом лэйауте, как для предыдущих кнопок. По типу элемента понимаем, что рисовать его мы не будем, но имеем новый комплект координат для привязки и новый список дочерних элементов. Рекурсивно проходим по нему, рисуя все, что по типу должно быть отрисовано и имеет признак visible==true.
Ну и примерно таким образом обрабатываются движения мыши, фокус элементов и все такое. Обход дерева родителей/детей и выяснение, что делать с текущим элементом в зависимости от его типа и установленных свойств. То, что какой-то элемент не QWidget, а QLayout, не добавляет параллельных иерархий, а уточняет в конкретный момент обхода дерева, что делать с элементом.
Поехали по порядку. Сперва кнопка, ищем правила ее отрисовки.
я достаточно глубоко разобрался в WPF с рисованием. Правила это обычно какая-то функция или вы не правильно выразились и речь идет не о правилах, а о параметрах для рисования.
Если рассмотреть этот пример, тут кнопкам не заданы ни координаты, не размеры, поэтому они-размеры должны быть посчитаны в какой-то момент.
Чтобы их посчитать надо вертикальный размер минус маргины поделить на количество чайлдов - это не правило это, логика компоновки которая где то существует как функция-метод класса. Эту функцию не надо искать ее надо просто вызвать.
Но третий чайлд у нас не кнопка, а лейаут и этому лейауту тоже определяются размеры и он использует эти размеры чтобы в них уже по своему горизонтальному алгоритму разместить своих чайлдов, то есть задать им размеры с помощью своей функции распределения размеров по горизонтали.
Я не думаю что можно придумать какую-то другую логику рисования-размещения, вопрос в том насколько близко к этому описанию реализована логика в QT, потому что в WPF она реализована очень близко к тому что я написал, с некоторыми нюансами относительно маргинов, паддингов и иерархии классов которая для этого используется.
а QLayout, не добавляет параллельных иерархий, а уточняет в конкретный момент обхода дерева, что делать с элементом.
я вот такие действия имел ввиду:
pvbxLayout->addLayout(phbxLayout);
и
pvbxLayout->addWidget(pcmdA);
Это же разные функции, можно предположить что они формируют разные независимые связи между объектами, эти независимые связи можно представить в виде разных иерархий. но я теперь согласен с вами работа идет с одной общей иерархией КуОбджектов в которую все они строятся. По типу объекта определяется что с ним делать, рисовать или дочерних компоновать, а потом рисовать.
Обход дерева кстати очень прост, рисуются все паренты (все объекты одного уровня), поверх уже нарисованного рисуется следующий уровень объектов, просто перезаписью байтов. То есть просто идем по дереву сверху вниз.
Правила это обычно какая-то функция или вы не правильно выразились и речь идет не о правилах, а о параметрах для рисования.
Насколько я знаю, нет фиксированного общепринятого или определенного в документации понятия "правило", где это функция, поэтому я не считаю, что я неправильно выразился. Я имею в виду совокупность условий, определяющих то, как параметр будет отрисовываться. Это может быть параметр, например, цвет. Это может быть функция, например, вычисление координаты правого угла из координаты левого угла и ширины. Это может быть набор функций, определяющих, где брать параметры и функции, например, сперва выяснить, кто у нас родитель и надо ли использовать координаты, прописанные в дочернем элементе или взять координаты родителя целиком, если в дочернем сказано "заполнить родителя". Поэтому я использовал расплывчатое слово "правила", если бы можно было сказать "параметр" или "функция", я бы так и сказал. Но я хотел обрисовать ситуацию очень грубо, поверхностно, не вдаваясь в детали. Логика компоновки зависит от класса отображаемых объектов, от свойств, заданных в них, от некоторых функций (методов), объявленных в них, от позиции их в иерархии родительствования.
Это же разные функции, можно предположить что они формируют разные независимые связи между объектами
Нас в первую очередь интересует, что они делают добавляемый объект дочерним для добавляющего. А так как лэйауты и виджеты имеют разных вторых корневых предков, функции тоже разные, иначе пришлось бы при вызове универсального гипотетического setChild проверять класс чайлда и выполнять соответствующие действия, определяющие детали реализации. А в действующем случае этот if или case возложен на программиста. Более того, таким образом можно сделать проверяемый на этапе компиляции запрет класть, скажем, кнопку прямо на форму мимо лэйаута.
И кстати, а что, это -
pvbxLayout->addLayout(phbxLayout);
компилируется? Когда я давненько уже работал с виджетами, так было нельзя...
Обход дерева кстати очень прост, <...> То есть просто идем по дереву сверху вниз.
Так и я же о чем. Если есть достаточно четкое представление об этом, то мне странно, что могло быть непонимание по поводу параллельных иерархий.
мне странно, что могло быть непонимание по поводу параллельных иерархий.
я просто искал аналогии с WPF. Там определены дерево визуальных обектов и дерево логических объектов:
Есть даже гибридное дерево:
Наследование значений свойств (Property Value Inheritance): Наследование значений свойств осуществляется с помощью гибридного дерева (a hybrid tree). Фактические метаданные, содержащие свойство Inherits, которое позволяет наследовать свойства, - это класс FrameworkPropertyMetadata на уровне платформы WPF FrameworkPropertyMetadata ...
для использования значений свойств родительских объектов дочерними объектами в дереве (наследование как использование дочерними).
чтобы знать, относительно кого использовать координаты и что с ними делать дальше.
кроме работы с координатами и в общем кроме рисования еще надо знать кому события от мыши/стилуса/клавиатуры диспатчить.
Но главное здесь - родитель/дочерний, для этого у них есть общий КуОбджект. Так что реальная иерархия тут только одна, восходящая к обджекту
Может я что-то не улавливаю, но менеджерам размещения вообще по барабану взаимоотношения родитель/дочерний QObject.
При конструировании формы, по сути создается своя собственная параллельная иерархия, которая отражает взаимосвязи на форме в формате "кто в кого вставлен".
Ибо: Когда новичек в Qt пытается осознать объектную иерархию конструкции, состоящей из основного виджета, менеджеров размещения (layouts) и подчиненных виджетов, ему легко сделать типичную ошибку: кажется, что основной виджет является родителем для менеджеров размещения, а менеджеры размещения являются родителями для подчиненных виджетов. На деле это не так
Когда дочерние виджеты "вставляются" в менеджер размещения через метод addWidget(), этот менеджер размещения не становится владельцем (т. е. родителем) дочерних виджетов. Он всего лишь знает о тех виджетах, которые в него "вставлены", и занимается только расстановкой этих виджетов на экране.
https://webhamster.ru/mytetrashare/index/mtb0/1628504234r3gp4s9cz9
И все же, а где обещанная шпаргалка?
ладно, понял. Вместо хэштега, видимо, для простоты поиска
"шпаргалка" это напоминание-подсказка, даже если что-то здесь сформулировано неправильно, одажды решив проблему мы о ней не забудем.
Лучше QML изучай. Виджеты используют всё меньше.
а QML виджетов нет? После того как QML загрузится он на объектах какого типа работает?
С точки зрения CPP - QQuickItem/QObject, с точки зрения QML - Item/QtObject. Но основная суть в том, что надо нарисовать QML-описание интерфейса в декларативном стиле (где допускается императивщина, но стоит постараться ее избегать где только можно), а логика вынесена в плюсы. Если сделать грамотно, то может получиться красивый вариант, где фронтенд так хорошо отделен от логики, что его можно почти безболезненно заменить на веб-морду или переписать на другой GUI-движок с минимальными проблемами.
я просто на WPF до этого рисовал вот например
тут вроде тоже самое, но маленько по другому.
Это действительно очень похоже на wpf, и здесь тоже есть соблазн напихать логики в описание gui, тем более что это очень просто, используя js
тем более что это очень просто, используя js
если код на С++ прикрутить к нему интерпретатор js для меня не реальная задача (или даже просто разбираться как с этим правильно работать), хотя у меня есть проект (из предыдущей статьи) в котором прикручены и питон и java, я не вижу смысла с этой связью разбираться, она енвайронмент-библиотеко зависимая очень, ее перенести куда то не реально, мне кажется.
Не надо ничего прикручивать, все уже украдено до нас. Пишем, например,
Button { }
И внутри скобок описываем, что хотим от кнопки - где, какая, признаки. Например, color: "red". Чтобы добавить императивщины, пишем onClicked: { } а в скобках js-код, который выполнится без лишних усилий с вашей стороны, причем, там можно использовать упомянутый color в качестве переменной, а также разные самостоятельно объявленные property.
Но идеологически вернее вместо кривых скобок сослаться на функцию, объявленную в плюсовом коде. Хотя можно столько логики впихнуть в qml-файл, что чертям тошно станет. И свои функции объявить в том числе.
Кстати, в qml можно объявлять сигналы и привязывать их к слотам в плюсах, а можно qml-функции привязать к плюсовым сигналам. В общем, есть где разгуляться.
И кстати, qml-элементы из коробки поддерживали тачскрин, включая мультитач. Не знаю, способны ли на это сегодня виджеты, но в свое время это была вообще киллер-фича для эмбеда
такого я не знал:
пишем onClicked: { } а в скобках js-код, который выполнится
то есть в QML встроен js-интерпретатор, правильно понимаю?
Единственное, насколькоя знаю и сталкивался, у них там документация очень скудная и/или поверхостная по объектам, свойствам, функциям, ... не говоря уже о типах взаимодействия этих объектов и методов, которые использовать можно, если у тебя нет готового примера вероятность того что найдешь всю информацию для своей идеи самостоятельно и в заданное время достаточно маленькая.
Во времена старинные в таких случаях говорили RTFM
встроен интерпретатор
ну, не совсем. Результат работы Qt компилируемый. Но с точки зрения создания кода это неважно.
А что касается документации, пардон, лучшей документации, чем встроенная в QtCreator, я еще не встречал. Исчерпывающая, с прекрасными перекрестными ссылками, с релевантными ссылками на подобные сущности, с отдельными статьями по правильности использования тех же раскладок, с примерами применения, с подборкой мини-проектов...
А что касается документации, пардон, лучшей документации, чем встроенная в QtCreator, я еще не встречал.
блин, не знал - не ожидал, я пока только со стороны смотрю, так сказать. Спасибо за информацию, значит надо будет QtCreator.все таки установить, если конечно проект не поменяется, что-то какая-то неопределенность в последнее время наблюдается.
Offtopic немного. Хотел в декларативном стиле писать интерфейсы на Lua под LOVE2D, вдохновился qml (ну и существующими библиотечками типа yui). Накатал вот это: . https://github.com/LRDPRDX/LikeliHUD . Сыроварня пока что, но работает.
Весь это код для gui... , по идее интерфейс нужно рисовать в редакторе, а не кодить, так сразу видно результат. Вот на визуале выстрелил delphi, там один из самых удобных редакторов интерыейса. Почему сейчас так не делают.
Во-первых, делают. В Qt тоже есть визуальный редактор интерфейса.
Во-вторых, это редко используется потому, что подходит только для примитивных окошек уровня калькулятора.
Хотя бы для интерфейсов адаптивных, где раскладка контролов зависит от разрешения, размера, ориентации (причем часть параметров может меняться рантайм на лету), польза этих редакторов сомнительна, зато надо заранее продумать раскладку (а не собирать мышью как лего), а тогда и редактор не особо нужен.
И не знаю, как ныне, но надысь редакторы так себе справлялись с самописными элементами. Если нужны не только стандартные кнопки/чекбоксы, то ой...
А для монстров, в которых интерфейс собирается на разного рода view (ListView, GridView и иже с ними) на основе настраиваемых моделей из БД, где может быть меню, определяющее состояние текущей страницы, на которой может быть десяток вкладок, на каждой из которых полсотни контролов либо динамически подгружаемые подстраницы, такие редакторы бесполезны абсолютно. А это, например, целая куча приборов, вроде современных цифровых осциллографов или мед. оборудования.
Если тем более в проекте работает дизайнер, который продумал и нарисовал хороший интерфейс в какой-нибудь фигме, берешь оттуда все координаты и цвета и переносишь в QML, опять же редактор GUI не нужен...
Если тем более в проекте работает дизайнер, который продумал и нарисовал хороший интерфейс в какой-нибудь фигме
а еще лучше если у дизайнера есть тул-бокс с объектами в которых он рисует свой дизайн, и если ему чего то не хватает в этом тул-боксе он (дизайнер) делает запрос на создание нового визуального объекта (или доработку существующего объекта), правда я про такой способ организации работы только слышал, никогда не видел :) может это просто сказки какие-то.
Даже в web есть компоненты и в андроид всякие фрагменты и этому не мешает необходимомть поддерживать разные разрешения экрана, чтобы куски интерфейса удобно комбинировать и реиспользовать. А если есть figma, то хорошо бы, чтобы она отдавала код на нужном языке, а не картинку.
Во-вторых, это редко используется потому, что подходит только для примитивных окошек уровня калькулятора.
Это крайне не верное утверждение. Вы здесь изначально видимо считаете, что визуальный редактор - это только про статичную форму. Накидал кнопочек и полей и вот тебе интерфейс. Но это далеко не так. И речь даже не о современных придумках, а о решениях десятилетней давности.
Тот же Delphi имеет в арсенале так называемые "фреймы". Фрейм - это элемент, который так же как и форма редактируется в дизайнере, только сам по себе фрейм не существует, а встраивается по желанию в форму (хоть в режиме дизайна, хоть в рантайме). Другими словами, фрейм - это визуально создаваемый контрол. И уже только этим инструментом можно оперировать как адаптивностью, так и динамичностью UI.
Помимо этого, если использовать современный Delphi и кроссплатформенный его фреймворк, то появляется возможность отдельно управлять тем, как будет отображаться контрол (фреймы, к слову, то же в нём имеются). Это работает так же как CSS. Элемент - отдельно, его представление - отдельно. Только и тут "CSS" (стиль) создается в отдельном дизайнере (это похоже на создание UI в Figma).
Если ты хочешь особый вид для конкретной кнопки - создаешь (визуально) стиль для неё, назначаешь стиль кнопке.
Если у тебя в интерфейсе есть одинаковые блоки из сложных элементов, например, элемент Dashboard, создаешь визуально фрейм конкретного элемента и вставляешь либо в дизайнере либо в рантайме фрейм в нужное место.
Если у тебя требуется сильная адаптивность, можешь создать разные фреймы под разное представление или реализовать адаптивность конкретному фрейму при изменении его размера.
И т.д. и т.п.
Так что вы заблуждаетесь в том, что "кодом оно всегда лучше, чем в дизайнере". Опять же в том же Delphi в дизайнере нет никаких ограничений по сравнению с кодом. Ты можешь все реализовать через дизайнер (относящееся к UI). А это значит, мы лишь получаем преимущество в скорости создания UI, если используем дизайнер.
Про стили в этом фреймворке я писал небольшую статью: https://habr.com/ru/articles/833804/
Правда там я не касался фреймов.
Про стили в этом фреймворке я писал небольшую статью
а что имеется ввиду под абревиатурой VCL в вашей статье, потому что у меня в предыдущей статье это библиотека в ЛибрОффисе. Может я где то пропустил человеческое описание на VCL?
VCL - Visual Components Library - это давний фреймворк для создания Win32 приложений в Delphi
https://ru.wikipedia.org/wiki/Visual_Component_Library
то есть, вроде как это оно и есть, только наверно какая-то ветка незнай когда обособленная. Спасибо.
Спасибо за ликбез, я знаю, как в Delphi. Но я привел пример интерфейса, который собирается на лету при запуске приложения из настроек, в БД или JSON, где каждый элемент определяется этими настройками. Здесь WISIWIG-редакторы бесполезны совершенно, ибо проектируется концепция интерфейса, а не его вид. Потом, кастомные контролы - это далеко не только кнопки со скругленными углами и нестандартными цветами, это может быть низкоуровневый код, определяющий логику работы компонента и его прорисовку в onDraw(). Можно научить редактор с этим справляться, но стоит ли овчинка выделки? Но самое главное - WISIWIG слишком много на себя берет, это кодогенерация, которая в определенных случаях вообще запрещена к применению из-за возможных неочевидных последствий (сертифицированных для уровня B WISIWIG-редакторов я не знаю, а это куча медтехники и авиаприборов). Банальный пример: простой SVG-файл, который я сделал вручную, примерно раз в 5 больше сгенерированного inkscape, хотя рисует то же самое. Или сложные таблицы во всяких вордах и либре гораздо менее предсказуемы, чем сделанные в LaTeX. Невизуальные редакторы дают полный контроль над результатом, а работу WISIWIG еще проверять надо, и чем больше эти результаты, тем больше работы по оптимизации.
Тащишь мышью кнопку на экран, примерно в левый верхний угол. Что должна кнопка делать при изменении размера окна или при повороте экрана - растягиваться, переползать, держаться каким своим углом за какой угол окна? Да, все это можно настроить в свойствах кнопки в панельке сбоку. Но если все равно это надо делать, это можно сделать и в коде, разница будет только в том, что я не мышью тащу в редакторе, а пишу Button { ... }. И мне не нужно наглядно вот прям щаз видеть глазами результат, я его отлично представляю себе, и первый же прогон приложения его подтвердит...
Если бы я действительно сильно заблуждался, WISIWIG-редакторы интерфейсов процветали бы, а в коде интерфейс стряпали бы единицы вроде меня. Но на практике я вижу, что их применяют в основном для окошек или фреймов уровня сложности не выше калькулятора.
Но я привел пример интерфейса, который собирается на лету при запуске приложения из настроек, в БД или JSON, где каждый элемент определяется этими настройками. Здесь WISIWIG-редакторы бесполезны совершенно, ибо проектируется концепция интерфейса, а не его вид. Потом, кастомные контролы - это далеко не только кнопки со скругленными углами и нестандартными цветами, это может быть низкоуровневый код, определяющий логику работы компонента и его прорисовку в onDraw().
Об этом и речь! Вы заблуждаетесь именно в этом. Всё это делается в том же дизайнере. Я повторяю, в очередной раз, дизайнер - это не обязательно конечный вид. Дизайнер - это редактор, ускоряющий создание интерфейса. Это может быть лишь часть интерфейса. Так или иначе, конечный интерфейс состоит из блоков.
Я могу вам легко продемонстрировать пример приложения, интерфейс которого вообще определяется бэкендом. Но при этом, всё создано в дизайнере. Потому что каждую часть интерфейса можно разделить на блоки и их создать в дизайнере.
И да! В фреймворке о котором я говорю (FMX) можно не только скруглить или поменять цвета кнопочек, а задать то как он будет отображаться и реагировать на пользователя. Задавать анимацию, триггеры, эффекты (применять шейдеры) и так далее. Стиль может влиять и на то ЧТО будет отображать контрол. Например, создать стиль кнопки у которой ДВЕ разных области с текстом или добавить/убрать иконку, или разделить кнопку на две (например, SplitButton) и т.д.
В этом фреймворке, контрол - это модель, а то как она будет выглядеть и в зависимости от каких условий определяет стиль, который создается через дизайнер. Стиль контрола может содержать и другие контролы, которые будут иметь свои стили. Кнопка внутри себя может содержать Grid или ListBox и всем этим можно будет управлять.
Помимо всего этого (речь только про Delphi), в дизайнере есть и биндинги, которые могут избавить от создания связей между контролами кодом.
Но повторюсь, если вас интересует именно гибкий, адаптивный интерфейс, то в Delphi я просто создаю фреймы - шаблоны, куски интерфейса, которых может быть много и для разных нужд. Если интерфейс сложный, в дизайнере окна создаются лишь области (слои), которые определяют, что где и как будет располагаться, дальше, создаются небольшие части интерфейса, которые ты можешь и в дизайнере поместить к окно и в рантайме создать когда нужно. Фрейм может содержать другие фреймы и может быть унаследован от другого фрейма и всё это в дизайнере. Фрейм может содержать внутри себя код, может быть реализацией интерфейса (interface, ООП, не UI), что позволяет запрашивать разные фреймы, реализующие нужный интерфейс для конкретного случая.
Ещё примеры: в Figma дизайнеры создают интерфейс из примитивов, обычно они сосредотачиваются на создании конкретного контрола и потом создают на основе него шаблон контрола. Так вот в FMX точно так же. Ты открываешь дизайнер стиля, создаешь из примитивов вид кнопки и он сохраняется как шаблон. И так со всеми контролами. Дальше ты переходишь на форму и можешь оформить интерфейс как тебе нужно. Это сейчас только про дизайнеров. Форму после этого можно не использовать напрямую, а разделить её на фреймы и и реализовать для этих кусков свою логику вывода данных. После чего ты на основе данных из JSON/БД создаешь интерфейс динамически.
P.S. минус не мой
Да бог с ним, с минусом, это неважно.
Я хотел сказать, что WISIWIG - отдельная концепция, которая имеет свои достоинства и недостатки. Главное достоинство - ускорение "разработки" (в кавычках - потому что это касается не только кода, но и, скажем, оформления текстов) и сиюминутная наглядность. Недостаток - подкапотная работа, порой кривая и небезопасная, иногда вообще неконтролируемая (в тот же DOC-формат лезть бесполезно).
WISIWIG безусловно крайне удобен тем, у кого нет ни времени, ни желания разбираться с используемой технологией, особенно если это одноразовая работа. Например, набор текста на пару страниц с кучей формул, скажем, лабораторной работы. Большинство ради одной-двух небольших работ возьмет условный ворд с его условным мат-редактором (как вспомнишь - так вздрогнешь). Но большинство тех, кому дорого время, качество и психическое здоровье, освоят что-то типа LaTeX.
Сегодня я и сам не выберу LaTeX (нет таких задач), но когда оформлял НИР, а еще несколько толстых брошюр с расчетом на типографию, этот замечательный инструмент показал мне всю мощь не-WISIWIG-редактора. Однако да, требуется определенный опыт или справочник постоянно под рукой. То же и с SVG, о котором я уже упоминал. Простые вещи делаются компактнее и логичнее, чем в основных редакторах, inkscape делает порой странную и избыточную структуру вложенных элементов, а первую треть тэгов можно безболезненно выкидывать. Сложные картинки - не знаю, вручную не делал. Если бы надо было делать регулярно - непременно попробовал бы.
У меня нерепрезентативная выборка среди своих знакомых, но по общению в интернетах сложилось ощущение, что WISIWIG реже используется там, где человек глубже погружается в технологию и стремится к более полному контролю. Когда ты и без WISIWIG представляешь себе то, что тебе нужно, он больше ограничивает, чем помогает. Возможно это дело вкуса. Но я и большинство моих коллег и хороших знакомых видят это так, и отсутствие мощных редакторов интерфейса для конструирования GUI и массового их использования это косвенно подтверждает. Возможно, я ошибаюсь. Не хочу никого переубеждать, просто мнение, по мере сил аргументированное.
Вас можно понять, но вы рассматриваете недостаток конкретных случаев, в данном случае SVG и LaTeX, но они работают не так как дизайнер в Delphi. Потому что в SVG и LaTeX можно получить визуально один и тот же результат разными путями. В SVG так тем более, потому что можно рисовать примитивами, а можно напрямую Path.
Но в дизайнере Delphi вид однозначно соответствует только одному коду (генерируемому), потому что генерируется не код, а лишь структура (формат, dfm/fmx). Формат структуры крайне прост, это просто дерево элементов с описанием того, кто кому является дочерним и какие назначенные свойства имеет.
object FrameChat: TFrameChat
Align = Contents
Size.Width = 1006.000000000000000000
Size.Height = 786.000000000000000000
Size.PlatformDefault = False
object RectangleBG: TRectangle
Align = Contents
Fill.Color = xFF343541
Locked = True
HitTest = False
Size.Width = 1006.000000000000000000
Size.Height = 786.000000000000000000
Size.PlatformDefault = False
Stroke.Kind = None
end
object VertScrollBoxChat: TVertScrollBox
Align = Contents
Padding.Bottom = 160.000000000000000000
Size.Width = 1006.000000000000000000
Size.Height = 786.000000000000000000
Size.PlatformDefault = False
TabOrder = 0
OnViewportPositionChange = VertScrollBoxChatViewportPositionChange
Viewport.Width = 990.000000000000000000
Viewport.Height = 786.000000000000000000
object LayoutTyping: TLayout
...
Это всегда однозначная структура и описать компактнее или "эффективнее" это не получится.
В коде это будет выглядеть так:
FrameChat := TFrameChat.Create(Self);
FrameChat.Align := Contents;
FrameChat.Size.Width := 1006.000000000000000000;
FrameChat.Size.Height := 786.000000000000000000;
FrameChat.Size.PlatformDefault := False;
RectangleBG := TRectangle.Create(FrameChat);
RectangleBG.Align := Contents;
RectangleBG.Fill.Color := $FF343541;
RectangleBG.Locked := True;
RectangleBG.HitTest := False;
RectangleBG.Size.Width := 1006.000000000000000000;
RectangleBG.Size.Height := 786.000000000000000000;
RectangleBG.Size.PlatformDefault := False;
RectangleBG.Stroke.Kind := None;
VertScrollBoxChat := TVertScrollBox.Create(FrameChat);
VertScrollBoxChat.Align := Contents;
VertScrollBoxChat.Padding.Bottom := 160.000000000000000000;
VertScrollBoxChat.Size.Width := 1006.000000000000000000;
VertScrollBoxChat.Size.Height: = 786.000000000000000000;
VertScrollBoxChat.Size.PlatformDefault := False;
VertScrollBoxChat.TabOrder := 0
VertScrollBoxChat.OnViewportPositionChange := VertScrollBoxChatViewportPositionChange
VertScrollBoxChat.Viewport.Width := 990.000000000000000000;
VertScrollBoxChat.Viewport.Height := 786.000000000000000000;
Но ведь на одном Delphi свет клином не сошелся, я говорю о WISIWIG-редакторах в целом. Это во-первых.
Во-вторых, представьте экран современного цифрового осциллографа, или монитора пациента, или панель бортовой системы управления малого самолета. Там море кнопочек, менюшечек, панелечек с табами, вкладками, которые находятся на фиксированных позициях разные в зависимости от активной страницы и предыдущих действий пользователя. Уровень вложенности страниц до восьми. Вы что, предлагаете это все "декомпозировать" и прорисовывать в редакторе? Да там вариантов сочетаний - как ходов в шахматах. Добавляется ListView или GridView, где и будут кнопки/табы. Их надо в большинстве случаев штук 5 на страницу - 4 стороны и центр. А модель для отображения берется в БД. Правила замены моделей при смене страницы (довольно простые) пишутся кодом, визуальный редактор тут не помощник. База наполняется отдельно, текстом и тоже довольно просто, по каждой потенциальной кнопке - ее вид, позиция (страница, например), зависимость от других кнопок, условия активности, связанный параметр и все такое. В результате умопомрачительные на первый взгляд по сложности и взаимозависимости интерфейсы делаются удивительно несложно, и смотреть в процессе разработки там не на что.
С дельфями я провел много замечательных лет, но даже их отличный редактор постепенно переставал использовать, чем сложнее был интерфейс и чем больше взаимодействий между состояниями интерфейса, тем проще это было выразить кодом. А декларативные описания интерфейса, типа QML/WPF (похожие, кстати, на результат работы редактора dfm) и вовсе настолько упрощают работу, что переключаться в визуальный вид просто нет реальной необходимости
Не сошелся, да, но это один из дизайнеров, так или иначе, и у меня с ним большой опыт и именно его я привожу в пример, потому что не вижу ни одной не решаемой задачи, которую вы приводите в пример. Для всего подобного давно есть решения: сменяющиеся элементы управления и прочее. Для всего этого есть решение через дизайнер.
Набор инструментов при разных режимах - это вообще очень простая задача (со стороны моего опыта).
Поймите одну вещь, дизайнер - это не только статичная форма, дизайнер помогает оперировать шаблонами UI. Разными частями. Глобально окно меняется редко, меняются отдельные части. Пусть и все в итоге до не узнаваемости. Но дизайнер не мешает строить такие интерфейсы.
Я повторюсь, но я делал приложение, интерфейс и механика которого полностью зависела от бэкенда. Там были и списки, и кнопки и поля ввода, всё это управляется с бэкенда. Но при этом сделано это именно в дизайнере, каждый элемент имеет свое представление, вид и механику работы.
дизайнер помогает оперировать шаблонами UI.
я работал только с WPF для редактирования UI. Там тоже есть понятия стилей, тригеров, шаблонов, ... Возможности просто огромны, но работать без справочника с таким богатством функциональности и даже слоев функциональности кажется не возможно без справочника особенно когда надо переключаться между разными средами разработки, но вопрос не в этом. Вы не знаете насколько понятия шаблонов вашей среды соответствуют-равны шаблонам WPF? Просто интересно что вы об этом думаете базовая идея должна быть та же, мне кажется.
Да все это я понял. Вы в свою очередь отказываетесь понять, что если задачу можно решить через дизайнер, то ее необязательно нужно решать через дизайнер. Ну вот есть такие, как я (и нас немало), кому дизайнер только мешает. Потому что и без него понятно, что выйдет в результате. Даже в дельфи я в конце концов ушел от использования дизайнера, хотя там он хорош, потому что он стал не ускорять, а замедлять меня.
Плюс работу с текстом я всегда предпочту работе с мышью, за что невзлюбил labview, вынужден был состряпать на нем пару относительно больших проектов, выбора не было. Но таки да, и у него есть свои поклонники.
Кстати, и в проектироавнии плис практически все серьёзные вещи пишутся на языке, а не рисуются в графике. В сети в графике только учебное баловство. И причины те же - полный контроль над деталями и отсутствие необходимости в визуальном наблюдении против не всегда корректной кодогенерации и пиксельхантинга
И я не совсем понял, что значит "управляется с бэкенда". Это нормально, вообще-то... но как дизайнер поможет собрать интерфейс из 5 элементов-контейнеров, если они элементарнейше укладываются и без него, и как он поможет наполнить базу корректными полями свойств контролов?
Проект не тот, что на скринах, он коммерческий. В нем реализована сборка интерфейса на стороне сервера. Т.е. сервер определяет какие элементы и как расположены в UI. Примерно как html, но свой формат, более специфический. Сделано так, потому что весь UI зависит от содержимого БД. В особенности, набор данных элементов.
Сложновато объяснить, но интерфейс полностью динамический, и каждый элемент является небольшой частью-шаблоном. И именно клиент управляет как будет выглядеть элемент. Сложность интерфейса может быть большой.
Сейчас у нас работают два клиента на основе такого сервера. На делфи и на реакте. И в Делфи куда компактнее реализация клиента и легче понять с чем работаешь.
Пример приложения

Это клиент для ChatGPT, я его создавал в позапрошлом году.
Вот так это выглядит в дизайнере

А вот так выглядит фрейм сообщения

Вот так фрейм чата

Узкое окно

Ещё более узкое. Мобильный режим




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