Последние несколько дней я пытался найти библиотеку, которая бы позволила мне писать на C++ программы с GUI. Мои требования были довольно просты:

  • Достаточно только поддержки Windows

  • Разрешено коммерческое использование

  • Простая стилизация, в том числе и тёмный режим

  • Результатом должен быть единый файл .exe размером меньше 40 МБ без или с минимальным количеством зависимостей

  • Написание части программы с GUI не должно занимать больше времени, чем сама функциональность

WinUI 3

На первый взгляд кажется идеальным выбором. Позволяет использовать современные компоненты Windows, в то же время допуская настройку цветов стилизации. Для дизайна можно пользоваться XAML, который очень легко освоить, или же напрямую работать с Visual Studio designer.

screenshot
Галерея элементов управления WinUI 3

Проблема: выпуск приложений в неупакованном виде поддерживается не очень хорошо. При попытках перенести приложение в VM или на другой компьютер чаще всего оно отказывалось запускаться из-за отсутствия каких-то непонятных зависимостей. Хуже того, в комплекте нужно поставлять несколько файлов .dll, управляющих функциональностью WinUI. Получить единый портируемый файл .exe никак невозможно. Использование упакованного вида обычно работает без проблем, но приложения устанавливаются как пакеты AppX, что привносит множество других проблем (особенно если вам нужен доступ ко всем Win32 API).

Win32 / MFC / небольшие библиотеки-обёртки для Win32

Мне нужна была высокая степень портируемости, так что логично было использовать нативный рендеринг операционной системы. Такая программа может быть единым файлом .exe (если мы статически компонуем MFC) и в то же время очень маленькой (всего несколько килобайтов). Можно было бы использовать и ещё более минимальную библиотеку, которую уже написали, что позволило бы мне быстро превратить концепцию в работающее приложение.

screenshot
Простая форма Win32

Проблема: стилизовать нативные элементы управления (controls) Win32 крайне сложно. Мне пришлось бы писать собственную функцию Paint для каждого элемента управления, что потребовало бы столько времени, что я бы успел ещё и обзавестись семьёй. Существует «тайный» тёмный режим для элементов управления Win32, используемый в Проводнике Windows, который можно активировать, но он охватывает только часть элементов управления и выглядит не очень красиво.

Qt

Эта библиотека — Святой Грааль GUI для C++. Хотя она довольно сложна, в ней есть удобная стилизация при помощи языка Qt Style Sheets, похожего на CSS.

screenshot
Использование Qt и собственных таблиц стилей в OBS studio

Проблема: при динамической компоновке для запуска приложения требуется куча разных .dll общим размером более 40 МБ. Можно статически скомпоновать Qt в программу, что существенно уменьшит её размер (так как неиспользуемые части удаляются), но тогда по лицензии LGPL Qt вам придётся сделать её опенсорсной или распространять в виде объектных файлов. Или же можно ежегодно покупать коммерческую лицензию за несколько тысяч долларов.

wxWidgets

Достаточно простая в изучении библиотека с опцией использования wxFormBuilder. Её лицензия менее требовательна, чем у Qt, и её можно статически скомпоновать в исполняемый файл размером 3 МБ.

screenshot
wxWidgets со включенной экспериментальной опцией тёмного режима в Windows

Проблема: в Windows эта библиотека использует нативные компоненты Win32 и не предоставляет никаких опций стилизации (так как мы не можем напрямую переписать функции Paint, она даже хуже, чем применение непосредственно Win32/MFC). Она поддерживает применение тёмных элементов управления Проводника Windows, но, как я говорил, они некрасивые.

hikogui

Довольно новая библиотека GUI retained mode, использующая в качестве бэкенда Vulkan. Имеет встроенный тёмный режим и достаточно проста в самостоятельной стилизации.

screenshot
Скриншоты из официального репозитория

Проблема: для успешной компиляции вам понадобится докторская степень по computer science со специализацией в разработке ПО. Потратив больше получаса на попытки скомпилировать пример (в том числе различных веток и меток релизов), единственное, что мне удалось получить — это исполняемый файл, немедленно вылетавший с ошибкой нарушения доступа внутри какой-то библиотеки Vulkan, поэтому я просто сдался. Проект выглядит очень многообещающе, хотя мне и не нравится активное применение надоедливой STL (без которой иногда даже можно было обойтись).

Sciter

Хорошая альтернатива Electron, позволяющая писать GUI для десктопного приложения на HTML/CSS.

screenshot
Пример плохого сглаживания SVG-значков

Проблема: вы могли подумать, что проблема будет заключаться в большом размере, но на самом деле готовое приложение со всеми .dll занимает около 25 МБ, что меня вполне устраивает. Библиотека могла бы быть ещё лучше, если бы она была опенсорсной и можно было бы пользоваться статически скомпонованной версией для коммерческого использования (та же проблема, что и у Qt). Она не такая дорогая, как Qt (сейчас $310 за лицензию Indie), поэтому я бы заплатил и был счастлив. Но проблема в том, что, как видно на скриншоте (посмотрите на значки заголовка окна), рендеринг неидеален. У меня возникали всевозможные проблемы со сглаживанием шрифтов и изображений. Кроме того, что бы я ни делал, у окна сохранялась довольно толстая (2-3 пикселя) серая рамка, которую никак нельзя ни настроить, ни изменить.

WinForms / WPF

Если вы начнёте спрашивать на форумах про GUI-библиотеки C++ для Windows, то чаще всего вам будут говорить, что это плохая идея (не спорю с этим) и что вместо этого вам нужно писать фронтенд программы на каком-то другом стеке, а затем просто загрузить свою написанную на C++ функциональность как компонент/модуль. Это позволит легко стилизовать её и сильно ускорить разработку. Теоретически, можно получить единый .exe небольшого размера и использовать WinForms/WPF. Это возможно реализовать двумя способами:

  1. Встроить .dll как ресурс в приложение и заставить его извлекать библиотеку в какую-то временную папку, а затем использовать P/Invoke и вызывать скомпилированную .dll из приложения на C#/.NET.

  2. Использовать C++/CLI.

screenshot
DarkUI для WinForms

Проблема: .NET Framework поставляется в комплекте с Windows 10+, так что, строго говоря, это удовлетворяет требованию отсутствия зависимостей. Проблема в том, что при встраивании .dll его всё равно придётся куда-то извлекать и писать дополнительный код для работы P/Invoke, а C++/CLI компилируется в код .NET IL (иными словами, можно открыть получившееся приложение в dnSpy и увидеть код на C++, транслированный в эквивалент на C#); мне же нужно не это, а нативный код).

Решение?

Это лишь некоторые из рассмотренных мной вариантов. После длительных попыток работы со всевозможными библиотеками и даже написания собственных стилей MFC я осознал, что для простых приложений нет ничего более подходящего, чем Dear ImGui.

У неё есть недостатки, в основном возникающие при попытке создания сложных UI; кроме того, это UI не retained mode, а immediate mode, так что только для рендеринга UI с частотой 60 или более кадров нам придётся задействовать GPU-рендерер наподобие DirectX.

Однако библиотека отвечает всем остальным требованиям, потому что DirectX по умолчанию встроен в современные версии Windows.

screenshot
Пример проекта ImGui AppKit

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

screenshot
Размер скомпилированного приложения ImGui AppKit

Скомпилированная программа весит всего 500 КБ и не требует ничего устанавливать, даже VC++ redistributable, если статически скомпоновать в него MFC.

Комментарии (41)


  1. vagon333
    01.07.2024 14:15
    +6

    При уважении к желанию Сэма (автора), есть прекрасный тост (из известного фильма) про желания и возможности.
    Если изначально UI либы созданы и поставляются как наборы DLL и ресурсов, то желание запихнуть все в один EXE-шник, а затем динамически распаковывать звучит так себе.
    Получается: либо свое, либо узкий набор решений.


  1. ImagineTables
    01.07.2024 14:15

    Странные утверждения, я бы сказал. Начиная от приложения, которое можно статически слинковать с MFC и в то же время оно будет весить несколько килобайт, до неотключаемой рамки у скайтеровского приложения. Да и остальное не лучше. Я бы сказал, это всё не случайные ошибки, а глубокое непонимание сути. MFC это не GUI-библиотека, а фреймворк для поддержания полного жизненного цикла документа, гуишная часть там вспомогательная, как и замена STL, если это понимать, можно не строить иллюзий по поводу небольшого размера (хотя, конечно, он всё равно будет сильно меньше, чем у Хромиума, гы-гы). Что касается Скайтера, он не занимается никакими рамками.


  1. bfDeveloper
    01.07.2024 14:15
    +9

    ImGui - шедевр, каких мало, но я бы не сравнивал его с Qt или WPF, это соврешенно разные весовые категории. ImGui идеально решает задачу отображения вспомогательных данных, простых кнопочек и крутилок конфигов, но сложные интерфейсы ещё и с высокой степенью кастомизации я бы на нём делать не стал.


  1. Wolf4D
    01.07.2024 14:15
    +4

    Как у ImGui с accessability? Она довольно далека от нативных элементов, всё-таки. И как у приложения с её использованием с энергопотреблением? Если я пишу условный калькулятор или какой-нибудь генератор отчётов с двумя кнопочками и одной областью просмотра - не заставит ли это пользовательское железо раскочегаривать мощности GPU?


  1. viordash
    01.07.2024 14:15
    +8

    а наследников Borland C++ нет уже?

    Судя по дельфи, создание UI в виндовс, это было совсем несложно. И ехешник единый можно получить


    1. TerrorDroid
      01.07.2024 14:15
      +4

      Оно около живое в виде Embarcadero RAD Studio, на бумаге выглядит очень интересно, но чёрт его знает как оно в жизни


      1. alan008
        01.07.2024 14:15
        +4

        Всё нормально, работает не хуже чем в Delphi 7 )


    1. mentin
      01.07.2024 14:15
      +1

      Там вроде нативные контролы - то есть отпадает по критерию стилизации и темной темы. Вообще без этого критерия всё было бы гораздо проще. Ну или если бы нативные контролы поддержали стилизацию (это уже совсем мечты).


    1. shybovycha
      01.07.2024 14:15

      не в С++, но в паскале был вроде опенсорсный Lazarus, но это ближе к Delphi


  1. TerrorDroid
    01.07.2024 14:15

    Было бы интересно посмотреть, что было бы при использовании RAD Studio — они вроде активно рекламируют кросс-платформернность, гибкий UI и мелкий размер


    1. Indemsys
      01.07.2024 14:15

      Вот статья где реализован симулятор файловой системы на C++ в RAD Studio. Весит 3 мегабайта. Сама файловая система не больше десятка килобайт занимает.
      Но меньше там не получить, потому что RAD тянет с собой огромный кусок библиотеки VCL с ресурсами если нужен единственный .exe


    1. alan008
      01.07.2024 14:15
      +1

      Кросс платформенные компоненты GUI (т.н. Fire Monkey) до сих пор какие-то странные/сырые, хотя появились лет 10 назад. Доверять в Delphi можно только старым компонентам VCL , но этот фреймворк не кроссплатформенный, он только под Windows


  1. xi-tauw
    01.07.2024 14:15
    +3

    стилизовать нативные элементы управления (controls) Win32 крайне сложно. Мне пришлось бы писать собственную функцию Paint для каждого элемента управления, что потребовало бы столько времени, что я бы успел ещё и обзавестись семьёй.

    В прошлой жизни, мне надо было перенести код с чего-то типа Borland C++ Builder на чистую студию, сохранив 5-6 кастомных "красивых" окошек. С одной стороны, там были только кнопки, рисунки, чекбоксы и эдиты, с другой - весь перенос занял у меня месяца два с полной поддержкой всяких радостей типа разных цветов для активной-неактивной-нажатой кнопки. Так что переписывание обработчиков WM_PAINT не настолько страшное, как представляется.


  1. AllKnowerHou
    01.07.2024 14:15

    Pyqt+pyinstaller


    1. Ikolo92
      01.07.2024 14:15

      Эм... Изначально поставили цель писать на C++. Ладно б вы ещё шарп посоветовали, но, если человек пишет на плюсах, значит 99% вероятность, что с питоном его задача не совместима априори



    1. Mark194
      01.07.2024 14:15

      Тогда уж Nuitka лучше, а то получишь кучу ненужных библиотек


  1. bogolt
    01.07.2024 14:15
    +5

    Win32/ImgUI/wxWidgets/Qt в одном сравнении ? Ну такое.

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

    Ну правда, ImGui и виджеты?

    Win32 и Qt ?

    Автор это очень очень разные штуки, если они у вас в одном сравнении вы вообще не понимаете что вам нужно.

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

    WxWidgets это полный простите пиздец, единственная ( сомнительная ) ценность которого это нативные контролы операционной системы. Впрочем может он за прошедшие 10 лет возмужал, но по моим воспоминаниям пользоваться этим нерабочим поделием было невозможно.

    Win32 - да можно, но это боль и бессмысленно низкий уровень. Если конечнь цель экономить кило/мегайбайты, чисто по фану то да, иначе просто бессмысленно.

    Qt - серьезный продукт на котором можно запилить как мини прогу так и большое тяжело приложение с чем угодно.

    (остальные решения щупать не доводилось ).


    1. dalerank
      01.07.2024 14:15

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


      1. bogolt
        01.07.2024 14:15

        Да я понимаю, но согласитесь сранивать ImGui с Qt это.. ну я не знаю даже... они разные настолько что области их применения почти не пересекаются. И там и там можно сделать кнопки но с совершенно разной сложностью и целями.

        ImGui крут когда у нас есть наш движок и нужно в него добавить пару кнопок, берем и делем. А Qt это же целый мир, если уже брать Qt то придется все на нем делать там соверешнно другая модель разработки и сложность собственно решений. Да и добавить Qt в уже существующий проект это ппц как дорого, а вот докинуть пару файлов imgui должно быть в разы проще. Короче я не понимаю зачем эти вещи в одном списке.


        1. dalerank
          01.07.2024 14:15

          Это да, хочется и красиво и код не писать. Автор похоже просто мечется в море ui фреймворков, не зная к какому берегу примкнуть. Из того что мне довелось пробовать можно добавить еще boden, cegui, elements, foxui, gltk, gacui, nana, mygui, nanogui, rml, xtd. И все небольшие, все можно скомпилить в пару сотен кб


        1. Dooez
          01.07.2024 14:15

          Возможно ImGui не так удобен если нужна стилизация. Нет разделения на форму и код. Нет встроенной поддержки системных тем.

          Но функционально на нем можно сделать наверное все, что может понадобиться в относительно нормальном интерфейсе. А с дополнениями вроде ImPlot вообще мощнейший инструмент с минимальными затратами на освоение.

          Мне искренне интересно, что по-вашему может Qt, что не получится сделать с Dear ImGui?


  1. SergeyPo
    01.07.2024 14:15
    +3

    Требование чтобы все было в одном файле, и ни в коем случае не было DLL -- выглядит как произвольное и не имеющее практической ценности. Если бы автор не выдумывал себе ограничений, то легко бы воспользовался например описанным им вариантом с WPF.


  1. Dark_Purple
    01.07.2024 14:15

    Я далёк от программирования окошек, просто интересно, виндовый anydesk на чем написан?


    1. DrMefistO
      01.07.2024 14:15
      +2

      Electron, Chromium based


  1. qiper
    01.07.2024 14:15
    +2

    Что насчёт бесплатной C++ Builder 11 Community Edition?

    https://www.embarcadero.com/ru/products/cbuilder/starter


    1. rPman
      01.07.2024 14:15
      +1

      Лицензия Community Edition применяется только в том случае, если совокупный годовой доход или иные поступления денежных средств Лицензиата (коммерческой организации, государственной организации или индивидуального разработчика) или любые пожертвования (некоммерческой организации) не превышает 5000.00 долларов США (или эквивалент в других валютах) ("Пороговый уровень"). Если Лицензиат является индивидуальным разработчиком, доход от всех подрядных работ, выполненных разработчиком за один календарный год, не может превышать Пороговый уровень (независимо от того, используется ли Community Edition для всех проектов или нет). Например, разработчик, который получает оплату в размере $5000.00 для одного проекта (или более $5000.00 для нескольких проектов), даже если такая работа над проектами не предполагает использования Community Edition, не может использовать Community Edition.

      это выдержка из лицензионного соглашения

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


  1. sergeym69
    01.07.2024 14:15

    Есть еще WTL https://wtl.sourceforge.io/ для чего то простого само то, программа будет маленькая и без каких либо зависимостей.


    1. mentin
      01.07.2024 14:15

      Если бы автор не хотел стилизацию и темную тему, то да - самое подходящее. А с требованиями стилизации отпадает.


  1. AndronNSK
    01.07.2024 14:15

    Всё гораздо интереснее, когда нужно выбрать кросс платформенный ui C++ фреймворк. Вот в этой ситуации и познаётся безысходность.


    1. DrMefistO
      01.07.2024 14:15
      +3

      Qt?


  1. GambitOZ
    01.07.2024 14:15

    Если нет конкретной привязки к языку программирования то C# (SharpDevelop) очень хороший редактор с приличным набором компонентов. Я в SharpDevelop обычно всякие гуяшные приложения и пишу.


    1. diverdm
      01.07.2024 14:15

      SharpDevelop же уже 10 лет как мертв?


      1. rPman
        01.07.2024 14:15

        это предок monodevelop, кстати который майкрософт выкупила и убила как конкурента vs



  1. snuk182
    01.07.2024 14:15

    WinUI это и правда былинный отказ, каждая версия SDK требует собственный рантайм, который при этом друг с другом даже в пределах патч-версий не дружит (про ошибку "There was no match for the specified key in the index" можно поэмы слагать.


  1. stasenso
    01.07.2024 14:15
    +1

    Про WIN32 API. Зачем для каждого элемента писать свой обработчик wm_paint, не понял? Если элемент нестандартный, можно использовать static стиль и рисовать в нём всё, что заблагорассудится, обрабатывая в едином стиле в одном wm_paint. К тому же, если нужен фон, то тут скорее WM_ERASEBKGND нужен. Вообще, мне опыт показал, что медлительность в разработке рождается от отсутствия сноровки. А когда сноровка есть, можно и на API и на любимом фреймворке написать с одинаковой эффективностью. Всё равно ни одного этапа разработки миновать не удастся.


  1. steam3d
    01.07.2024 14:15

    Упакованные приложения WinUI3 прекрасно работают с WinAPI. Скорее, проблема в том, что Microsoft постоянно бросается от одного проекта к другому, в итоге имеем кучу разных платформ с плюсами и минусами в каждой.


  1. rPman
    01.07.2024 14:15
    +1

    Когда то давно давно, когда msvc только вышагивали как замена win32 gui, я пытался (к сожалению показать нечего, весь мой код с того времени потерян) разработать кодогенератор для win32 gui, который буквально брал на себя весь неудобный и муторный код, делая разработку именно интерфейса простым мышевозекательным (смутно помню я еще в качестве текстового редактора кода использовал far commander с кучей плагинов, заточенных именно на c++ разработку), а позже появился .net c# и winforms (тоже генератор кода но уже в своей экосистеме, и даже пофиг было что это медленно работало) и в этом отпала необходимость... очень странно что майкрософт буквально угробила эту замечательную технологию, заменив ее wpf а потом и ее испортило (разработка из интерфейса на столько нестабильна, что даже странно)

    Никогда не понимал потребности разработчиков в темах и смене внешнего вида приложений, за исключение того что предлагает ОС (те же linux kde/gtk), меняя расцветку и форму контролов единообразно. Любые попытки уйти от централизации выглядят неадекватно и криво в результате.

    Именно из-за этого маразма, я могу встретить в одной установке xfce приложения с кардинально разным порядком размещения save/do not save/cancel, с разным способом отображения выбранной кнопки (в т.ч. без), т.е. речь идет даже не про темы, а про базовые правила разработки приложений. Когда приложения от ubuntu теперь имеют свой механизм оформления, отказываются принимать классическое поведение окон (например перенос средней кнопкой мыши за край окна) и прочие мелочи, которые определяют комфорт работы.


  1. Emelian
    01.07.2024 14:15

    Разработка интерфейса для Windows — это боль

    Если смотреть на проблему в целом, то да, идеальных вариантов нет. Все существующие фреймворки для С++ хороши для своих собственных ниш.

    Здесь, вроде бы, еще не упомянут Win32++ - аналог MFC, в исходных кодах ( https://sourceforge.net/projects/win32-framework/ ). Кстати, кажется, и сам M$ выложил уже в открытый доступ исходники MFC. Раньше это могло быть интересным, сейчас уже нет.

    Лично я попробовал разные варианты, но, в итоге, вернулся к WTL. Для моих целей, вроде написания обучающих программ, это самое то. Смотрите, для примера, скриншоты моей программы:

    http://scholium.webservis.ru/Pics/Lecole.png
    http://scholium.webservis.ru/Pics/Lecole2.png

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

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


  1. Panzerschrek
    01.07.2024 14:15

    Qt не так уж и плох, если его уметь правильно готовить. Если использовать какую-нибудь не очень новую версию (скажем, 5.12) и грамотно обработать зависимости (через windeployqt), то результирующая сборка программы может уместиться в 40 мегабайт. Да, там будут dll, а не один exe, но в этом значимой проблемы я не вижу.