Комментарии 55
Здравствуйте! Спасибо за статью!
Небольшой совет, для улучшения читаемости код лучше поместить в специальный блок:
![](https://habrastorage.org/getpro/habr/upload_files/df5/046/d93/df5046d930fbb16148648db3688bcd57.png)
Приветствую!
Да вроде так и делал, все что можно было в блоки код добавил.. но подсветки синтаксиса почему-то нет. Возможно там как-то надо указать ему что это вот c++, а это json
При попытке скачать демо-приложение с сайта https://libwui.org/ Windows Defender сказал, что обнаружен вирус
Гигантская работа...
Хотел спросить, а почему был выбран подход sleep в случае GNU/Linux?
Там же есть poll, epoll, т.е. можно "нативным" образом "ждать" не жертвуя временем в функции ожидания. Там какой-нибудь контроллер сработал и пнул пулл событий, тогда поток проснулся и обработал их. Под Windows что-то похожее было типа WaitForMultipleObjects
Я понял про какой вы слип. Он используется в цикле не дающем функции main завершиться. Там можно спать хоть по секунде, его задача просто узнать не закрыл ли юзер главное окно и дальше отдыхать...
Ну вы не учли фатальный недостаток этих систем )
Приветствую.
Покритикую немного:
код примера окна написан плохо: #ifdef _WIN32 int APIENTRY wWinMain и тд пользователю это зачем. Если так придется писать везде, то не представляю как будет выглядеть приложение от 10к строк
в репе код тоже страшен
нет разделения кода для разных ОС, все склеено как и в примере #ifdef по месту
класс window.cpp весь в одном файле и занимает 3к строк кода, все остальные классы так же устроены
есть такая вещь как регистр символов, у вас классы, структуры, обычные переменные, статич переменные и тд - все в нижнем регистре. Как вы их отличаете?
что еще.. ладно
В общем, обычная поделка, долго не протянет.
Если хотите дальше упражняться, то сравните размеры wxwidget и того что у вас есть сейчас, прикиньте сколько еще бежать, может с пользой лучше энергию потратить?
Совет: возьмите wxwidget, добавьте туда удобную настройку графики (аналогично css на вэбе, или qss в qt), мне вот только ее не хватало, когда работал с wxwidget, остальное там все уже есть.
Вы не зрите в корень... wxWidgets с дизайном из начала 90х, против максимально приятного modern c++ да ещё и без шаблонной жести...
Насчёт "поделия", то это сделано для коммерческого продукта который решает боевые задачи и зарабатывает деньги компании.
Что до одного файла - "по уму" надо сделать "стратегии" а ля Александреску, но прямой путь зачастую выгоднее и проще в плане онборднига. Это все детали реализации.
Я же хотел привлечь внимание к тому, что UI может быть более прямым чем все мы привыкли.
wxWidgets с дизайном из начала 90х
внутри дизайн из 90х вы имеете ввиду, и что, его не надо переписывать, он работает, обкатан на большем количестве пользователей, чем ваше изделие. А снаружи wxWidgets не хватает только удобной настройки стилей виджетов, больше ничего. Шаблонной жести там тоже не много. Ладно, дальше не буду спорить.
На счет денег компании, не всегда продукт решает, есть еще лапы мохнатые, личные договоренности и тд. А как работают пользователи - кто его знает, и сколько времени занимает добавление новой фичи, тоже не известно, остается только вам поверить, что "немного".
Эхх, были бы эти "личные договоренности" я бы донаты не собирал ))
Про дизайн из 90х я имел ввиду прежде всего дизайн интерфейсов. А дизайн wxWidgets/MFC/WTL строился вокруг системного API во время ещё до c++98...
Современный C++ гораздо гибче, приятнее и лаконичнее, так что писать прием сообщений на макросах нет никакой нужды. Так же как и запихивать интерфейсы контролов в прокрустово ложе устаревших API и концепций авторов, которых уже некоторых нет в живых...
о каком "modern C++" идет речь, если вы из конструктора исключение не выбрасываете?
и писать кросс платформу на #ifdef... ну это уровень студенческого диплома
Почти под всеми пунктами подпишусь, сам проходил когда-то через такой способ написания и поддержки кросс-платформенного кода и убедился в том, что это прямой путь к росту проблем по мере старения кода.
Но вот это вот:
есть такая вещь как регистр символов, у вас классы, структуры, обычные переменные, статич переменные и тд - все в нижнем регистре. Как вы их отличаете?
вы зря. В C++ нет де-юре официального code style, каждый проект имеет право использовать то, что нравится больше всего.
Соглашусь с критикой. Директивы условной компиляции типа #ifdef __WIN32 и им подобные, подразумевают что между ними будет платформозависимый код. Таки и смысл перекладываться подобную условную компиляцию на плечи пользователя библиотеки? Не грамотнее было бы сокрыть платформенно зависимые вещи внутри кода своей библиотеки? О какой такой "кроссплатформенности" при таком подходе можно заявлять?
Все #ifdef _WIN32
приложения (не библиотеки) имеются только в файле где находится точка входа int main(...)
Можно сделать два файла а-ля: main_win.cpp, main_lin.cpp
и обойтись вообще без #ifdef _WIN32
платой за это, станет дублирование части (довольно хорошей) кода функции main()
Этот файл с функцией main, вообще такое место, куда обычно никто не лазит, там ничего нового - инициализация конфига, логгера (если есть в приложении), темы и локали.
Весь пользовательский код, пишется в классах реализации окон, и там никаких #ifdef _WIN32
обычно нет. Ну если вам не нужно, например, работать с аудио / видео, так как системные API очень отличаются. Тут мы уже делаем как раз camera_lin.cpp / camera_win.cpp
потому что дублирования кода практически нет.
Как на линуксах с пользовательскими настройками? Ну иконки/темы в пролете, я так понимаю, да и ладно, а что насчёт масштабирования на high DPI?
Смотрите, размер окна и все координаты контролов отображается 1 в 1 на экране, так как задается в пикселях. Т.е. с этим проблем нет, приложение имеет одинаковую геометрию на Win (при масштабировании 100%) и на Lin. Одно но - при использовании одинаковых шрифтов.
Я на Линукс затащил шрифты с Винды и кайфую )) тот же Телеграм в 100 удобнее читать стало. При использовании например Open Sans вместо Segoe UI, размер 14 Segoe выглядит на Linux + Open Sans на все 18. Это пока решаем поставкой тем для лиункса с уменьшенными размерами шрифтов на 4.
Самым грамотным решением, я считаю, как сделано в lvgl - тащим шрифты с собой и получаем, хоть на bare metal, пиксель в пискель то что мы хотим.
Так вот и проблема в том, что пиксель в пиксель, и при использовании масштабирования приложение будет выглядеть коряво. Вот как выглядит Java Swing приложение - часть элементов масштабируется, часть нет.
Скриншоты
![Большое разрешение с масштабированием, Swing приложение выглядит криво Большое разрешение с масштабированием, Swing приложение выглядит криво](https://habrastorage.org/getpro/habr/upload_files/ee2/b74/dac/ee2b74daca1c3301bb023d5e979a66fa.png)
![Большое разрешение без масштабирования, все приложения выглядят одинаково Большое разрешение без масштабирования, все приложения выглядят одинаково](https://habrastorage.org/getpro/habr/upload_files/7f9/c06/4d4/7f9c064d4dc4ecfe05fcc651204f5d82.png)
![Разрешение поменьше без масштабирования, все приложения выглядят одинаково Разрешение поменьше без масштабирования, все приложения выглядят одинаково](https://habrastorage.org/getpro/habr/upload_files/427/d8f/71a/427d8f71ab718bc9d9822e8c4125fd5f.png)
В вашем случае скорее всего все элементы останутся неизменными и будут выглядеть мелко.
Весьма круто, надеюсь сделаете на macOS чтобы работало. Делали ли уже публикацию на Reddit? Стоит попробовать собрать донаты на уровне стран первого мира - тут вам максимум копейки накидают - разве что как-то подсесть на гос. заказы.
Да какие донаты, это как в деда мороза верить )
Я вообще бы хотел платить за разработку новых / улучшение имеющихся контролов...
Например проводим конкурс на лучшую реализацию мнострочного редактора, победитель получает деньги, а все сообщество получает его контрол включенным в официальную поставку. Это как-то больше похоже на опен сорц здорового человека, как мне кажется...
Публикация пока первая, Реддитом займемся ?
Про wx: если вы не любите кошек, то это значит, что вы не умеете их готовить.
Я всех люблю ?
Посмотрите лучше: https://lvgl.io/
wx отдыхает, как и wui ?
static constexpr const char* IMG_LOGO = "logo.png";
Для полного счастья надо было ещё unsigned добавить. Вы кажется не очень понимаете, как работают constexpr выражения.
Планируется ли сделать нормальную архитектуру, чтобы пользователь мог сделать какой-нибудь gui->run()
и не обмазываться миллионом платформенных дефайнов?
Планируется ли перейти на string_view
вместо string&
?
Спасибо за замечания по constexpr ?
По поводу платформенных кишков с ifdef
вопрос уже решен - создана новая подсистема framework.
Теперь минимальный hello_word выглядит как-то так:
#ifdef _WIN32
int APIENTRY wWinMain(_In_ HINSTANCE,
_In_opt_ HINSTANCE,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
#elif __linux__
int main(int argc, char *argv[])
#endif
{
wui::framework::init();
// Здесь код инициализации конфига, темы и локали
MainFrame mainFrame;
mainFrame.Run();
wui::framework::run();
return 0;
}
MainFrame.cpp:
window->init(wui::locale("main_frame", "caption"), { -1, -1, width, height },
wui::window_style::frame, [this]() {
wui::framework::stop();
});
Сейчас еще сделаю селектор для конфигов и обновлю статью.
Вам, и всем кто указал на эту недоработку огромная благодарность ?
Существенно переписал раздел "Главный цикл приложения". Теперь #ifdef'ы не торчат и все красиво. Спасибо еще раз за критику.
По stringview нужно подумать, скорее всего если c++14 на XP соберется то сделаем.
Дык ежели вы все эти HInstance не используете, то простой `int main()` должен завестись без проблем
почему сразу делалось не на Qt [...] это связано с [...] любовью к монолитным exe
Можно собрать статический Qt и линковать с ним, будет тоже монолитно.
Кстати, интересно, какой у вас получился финальный размер релизного бинарника/exe? Статический Qt (Quick, не Widgets) с лёгкостью бы накинул 20-30 МБ для среднего приложения (одно окно, простые/стандартные графические эффекты, сеть).
>while (runned
Кажется вам не только Qt не нравится, но английский язык тоже, нужно переписать таблицы сильных глаголов! :)
В пикселах - это, конечно, хорошо. На мониторах 4К мелко не будет это всё?
Будет мелко, однозначно. Поддержка DPI и svg скоро, надеюсь, будет.
Пока есть workaround - сделать 4K темы. Контролы автоматически увеличатся под текст. Но это такое, да...
Еще надо декларативный язык для создания UI и редактор...
... и получить на выходе Qt! /s
4K это такая штука, про которую если на этапе проектирования забыть/забить, то потом придется всё перелопачивать.
Спасибо!
Я пока думаю следующее:
1. Для ряда задач нужно пиксель в пиксель (условный embedded)
2. Для десктопа нужна читаемость/попадаемость мышью, т.е. нужен некий scaling.
Возможно я что-то упускаю, как я сейчас думаю это сделать:
2.1. Простой случай: просто умножаем координату/размер на scale factor
2.2. Для сложных приложений возможно лучше отдельное UI представление с другой компоновкой для 4К. Т. е. если у нас стало в 4 раза больше экрана, а кнопок у нас как в условном автокаде, то имеет смсыл показать больше кнопок/инструментов.
Вообще интересно что вы думаете про подводные камни 4К, и какие есть пути решения...
Достойно. В своих проектах тихонько отхожу от Qt . По максимуму использую стандартные библиотеки (например std::thread вместо QThread, контейнеры, типы (qint64 в std::int64_t). Выбросил сигналы и слоты (замена на std:: functional и лямды). В результате собираю проект без moc компилятора.
Все виджеты из-за особенностей свои (отрисовка только QPainter).
Тоже хочется свой велосипед сделать в интерфейсе.
Достойно. В своих проектах тихонько отхожу от Qt . По максимуму использую стандартные библиотеки (например std::thread вместо QThread, контейнеры, типы (qint64 в std::int64_t). Выбросил сигналы и слоты (замена на std:: functional и лямды). В результате собираю проект без moc компилятора.
Я тут тоже подумываю как с Qt уйти, ибо не бесплатный он (постоянно все об этом напоминает). У меня небольшой вопрос: как из лямбды послать в другой поток данные. Есть там нюансы? То есть раньше я использовал сигнал/слот и он потоко-безопасный был. А теперь лямбдой как?
"Методы, которые могут завершиться ошибкой возвращают bool..."
Для 2023 это как-то уже не камильфо... Как привет из древности)) Есть же промисы/фигомисы, какие-то современные концепции, которые за счет С++ inline будут достаточно эффективны. Эти IF с поверками кода ошибок, как крик из девности ))
Гора "wui::locale()" выглядит так себе...
Можно было бы хотя бы локальные макрос/inline функция вставить, чтобы это выглядело покороче, например LT("main_frame", "caption"), а еще лучше LT("main_frame/caption")
Опять гора static_cast выглядит тоже ободряюще )) Может как-то можно избавиться от необходимости в этих кастах.
Я думаю, вы со временем привыкли игнорировать эти мусорные части кода, но для неподготовленных (привыкших писать/читать лаконичный код на Kotlin, scala и т.д.) это выглядит так себе.
В примерах на С++20 можно применять using enum wui::menu_item::menu_type;
(или какие там у вас тип), чтобы избежать этой боли для глаз с длинными дублирующимися выражениями wui::menu_item_state::normal, wui::menu_item_state::normal, wui::menu_item_state::separartor.
По поводу Mac: пользователи Mac любят, чтобы выглядело как на Mac... поэтому ваши самоотрисовки выбор для Mac не очень удачный. Эта же проблема была с Java Swing под Mac и Windows XP, отрисовать так красиво как нативно не получилось и обычным разбалованным пользователям это не очень нравилось.
Просто для медицины (и для внутренних корпоративных приложений) это не важно как и что отрисовано (главное чтобы работало), а вот для обычных приложений (у которых есть конкуренты) это может быть очень важно.
PS: В молодости тоже страдал чем-то эдаким (только без само-отрисовки на С++), а ля что-то своё, но более С++-ое и современное и более маленькое чем MFC. А с отрисовкой писал под Java 1.1 (частично крал код и/или идеи из Java Swing) :-) ))))
Глянул сейчас репу. Круто, улучшения весьма заметные!
Спасибо за проект с открытым кодом, давно жду кто первым сделает и выложит свою отрисовку гуя. Очень признателен. Лицензия буста как я понял из гитхаб?
Опыт создания UI библиотеки на C++