Предисловие


Некоторое время назад мне понадобилось написать некое консольное приложение для собственных нужд. Но так как это было бы слишком просто, было решено прикрутить к нему некое подобие GUI.

Блуждая на просторах интернета, мне удалось найти только две библиотеки для .NET, которые, возможно, удовлетворили бы мои потребности: MonoCurses и CursesSharp. Но эти библиотеки целиком и полностью заточены под ncurses — *nix-библиотеку для управления терминалом, и с Windows если и вообще совместимы, то очень плохо. В итоге возникло единственное решение написать свой велосипед.

Функционал


Кроссплатформенность

GoddamnConsole полностью совместим и с Windows (используется WinAPI), и с Linux (используется ncurses), и, возможно, даже с другими Unix-подобными ОС (Mac OS X, FreeBSD).

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

Визуальные компоненты

Компонент — основная единица UI библиотеки. Для написания своего компонента достаточно просто создать наследника класса Control и переопределить пару методов (отрисовка, события клавиатуры). Также доступно несколько встроенных компонентов:

— TabControl — компонент, использующийся для создания вкладок. Переключение вкладок происходит по нажатию на стрелку вправо и влево.

— TextView — компонент для отображения текста.



StackPanel — простейший контейнер, укладывает дочерние элементы в столбец или строку.



Кстати, это пример компонента, у которого даже не переопределен метод отрисовки — т.е. сам он ничего не рисует.

— Grid — контейнер, представляющий собой сетку элементов. Очень похож на одноименный компонент из WPF.
GridWindow дублирует функциональность этого контейнера, за исключением того, что GridWindow самостоятелен, а Grid — нет.



— TextBox — компонент для отображения и ввода текста. В отличие от TextView, захватывает фокус и поддерживает скроллинг.



— Button — кнопка. Имеет событие Clicked, вызывающееся при нажатии на Enter.



Независимость от размера консоли

Независимость от размера консоли — очень важный элемент консольного (да и вообще любого) UI, так как терминалы *nix поддерживают свободное изменение своего размера. А с недавних пор такая возможность была добавлена и в Windows 10.

Как это использовать?


Для использования библиотеки вам достаточно скачать последний релиз библиотеки из репозитория GitHub и добавить ссылку в проект на нее. Кроме того, вы можете скачать исходники и самостоятельно скомпилировать их. В случае Linux с компиляцией могут возникнуть проблемы из-за того, что xbuild не умеет собирать проекты .NET 4.5. Вам потребуется либо собрать библиотеку вручную (инструкция будет позже), либо воспользоваться компьютером с Windows.

Простой пример использования:

using GoddamnConsole.Controls;
using Console = GoddamnConsole.Console;

namespace GoddamnConsoleSample
{
    internal class Program
    {
        private static void Main()
        {
            var window = new ContentWindow();  // создание окна
            window.Title = "Sample Window";    // установка заголовка окна
            var text = new TextView();         // создание текстового поля
            text.Text = "Hello, World!";
            window.Content = text;             // установка содержимого окна
            Console.Windows.Add(window);       // добавление окна в консоль
            Console.Start();                   // запуск консоли
        }
    }
}

Результат:



Кроме того, в репозитории вы можете найти пример, который охватывает практически всю текущую функциональность.

Заключение


Библиотека еще не готова полностью, но она вполне пригодна для построения простых (и не только) приложений.

Некоторая функциональность в статье не описана (например, Data Binding) в следствие ее недостаточной завершенности. В дальнейшем планируется добавить больше компонентов, добавить новую функциональность и отладить существующую.

С удовольствием отвечу на все вопросы в комментариях, если возникнут.

Отдельное спасибо сайту govnokod.ru за помощь в костылировании под линукс.

Ссылки

Поделиться с друзьями
-->

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


  1. rbobot
    06.07.2016 12:10
    +1

    Красота. Надо будет из powershell ее заиспользовать.


  1. lair
    06.07.2016 12:12

    Для использования библиотеки вам достаточно скачать последний релиз библиотеки из репозитория GitHub и добавить ссылку в проект на нее.

    NuGet?


    1. zawodskoj
      06.07.2016 13:10
      +1

      Будет и в нугете, но чуть позже


  1. Vjatcheslav3345
    06.07.2016 12:33
    -4

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


    1. lair
      06.07.2016 12:49
      +1

      А зачем? Какой от этого выигрыш для обучаемого?


      1. zawodskoj
        06.07.2016 13:36
        -2

        Возможно, не выходя из консоли, учить принципы WinForms/WPF, ибо довольно похоже


        1. lair
          06.07.2016 13:38
          +5

          Что мешает их учить сразу на WinForms/WPF (не говоря уже о том, что это, на самом деле, несколько разные принципы)?


  1. bobermaniac
    06.07.2016 12:44
    +14

    Ух ты, TurboVision!


  1. svekl
    06.07.2016 12:56
    +3

    Какая прелесть, хорошо бы ещё ProgressBar.


  1. impwx
    06.07.2016 12:58
    +2

    Прямо захотелось написать плагин, позволяющий описать такой интерфейс в виде XAML.


    1. zawodskoj
      06.07.2016 13:25
      +1

      Крутая идея. Учитывая то, что скоро подвезут полноценный Data Binding, писать на XAML получится почти так же, как и под WPF.


      1. Melz
        06.07.2016 13:52

        Такие проекты были для WPF, но не взлетели.


    1. Indexator
      07.07.2016 06:17

      Ага, а еще, чтобы в визуальном представлении можно было накидать и посмотреть! :D
      JSON тоже было бы неплохо. :)


    1. Athari
      12.07.2016 15:46

  1. Melz
    06.07.2016 13:52
    +1

    Ух ты!
    Мне периодически такое хотелось сделать. Я смотрел на MonoCurses, но там последний коммит 8 лет назад.
    А CursesSharp точно под Win не работает? Там написано что он через CursesSharp все делает.


  1. mnakamura
    06.07.2016 14:20

    О, кстати, а расскажите, можно ли у вас в Windows выводить на консоль такие символы, как U+2014 (—), U+2E3A (?) или U+2E3B (?), как это будет выглядеть и сколько знакомест занимать? Как вы вообще решали проблему с разной шириной моноширинных символов — wcwidth() по идее есть только в ncurses, какими-то словарями, EastAsianWidth.txt или чем-то таким?


    1. zawodskoj
      06.07.2016 14:35

      Странная проблема, не столкнулся с такой


      1. mnakamura
        06.07.2016 15:08

        Ну, вы же как-то считаете длины строчек — сколько знакомест будет занимать выведенная на экран строка?


        1. zawodskoj
          06.07.2016 15:21

          Один символ — одно знакоместо


          1. mnakamura
            07.07.2016 14:21

            Понятно. К сожалению, в реальности все не так просто: какой-нибудь ? занимает два знакоместа, а есть еще символы вроде приведенных выше, которые занимают по три. В ncurses есть для этого такая функция, как wcwidth(), а вот как это делать без ncurses мне всегда было интересно. Вот ниже подсказывают, что тоже хорошего решения не нашли.


    1. iqiaqqivik
      06.07.2016 16:29

      > проблему с разной шириной моноширинных символов
      Моя консоль (gnome-terminal) просто начинает рисовать следующий символ в позиции «текущая + ширина m», прямо поверх всех этих дашей. Я не думаю, что это проблема библиотеки, я думаю, это вопрос алгоритма отрисовки моноширинного шрифта консолью.


    1. xaizek
      06.07.2016 20:05
      +1

      Когда мне это понадобилось на Windows, я просто взял ту же реализацию, что используется в ncurses (лежит здесь). Как это сделать через WinAPI, я не нашёл. Если просто выводить такие символы по соседним координатам, то каждый второй пропадёт. Может работать нормально при обычном выводе типа WriteFile. Но если рисовать через WriteConsoleOutput, чтобы можно было задавать атрибуты для каждого символа отдельно, то надо вставлять "пропуски" c нужными атрибутами, чтобы всё нормально отображалось.


      1. DeXPeriX
        16.07.2016 12:04

        Не подскажете, какие именно атрибуты нужны для «пропусков»? И где про это можно почитать? Японские иероглифы консоль сможет отобразить, если Windows русская?


        1. xaizek
          16.07.2016 12:20
          +1

          Не подскажете, какие именно атрибуты нужны для «пропусков»?

          Те же, что и для самих символов. Я так патчил для pdcurses.


          И где про это можно почитать?

          На MSDN я не увидел такого требования (может не заметил), но сделал так и всё начало отображаться нормально.


          Японские иероглифы консоль сможет отобразить, если Windows русская?

          Должно, я с китайскими пробовал на английской Windows. Единственное, шрифт должен уметь их выводить. В cmd.exe оно просто так не работало (квадраты вместо символов, но при правильном шрифте должно отображаться), а ConEmu отображало все иероглифы правильно изначально.


    1. bolk
      06.07.2016 21:15
      -1

      Разной шириной моноширинных символов? Реально есть такая проблема? По мне так взаимоисключающие параграфы.


      1. xaizek
        06.07.2016 21:22
        +1

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


  1. alex1t
    06.07.2016 14:32

    А прокрутка и скролбары есть?


    1. zawodskoj
      06.07.2016 14:33

      Прокрутка есть, скроллбаров пока нет


  1. bmforce
    06.07.2016 14:55
    +2

    В своё время наткнулся на такую библиотеку:
    https://github.com/elw00d/consoleframework


    1. zawodskoj
      06.07.2016 15:11

      Интересная библиотека, но развивается довольно медленно


      1. elw00d
        06.07.2016 18:12

        Да, к сожалению, это так. Выяснилось, что это мало кому нужно. Хотел заняться ей плотнее после выхода .NET Core, но там отпилили режим build --native, а очень хотелось попробовать именно в этом режиме позапускать. Но в любом случае, буду пробовать портировать на .NET Core, а там может быть и нативный режим прикрутят.


      1. Athari
        12.07.2016 15:51

        У вашей библиотеки есть какие-то принципиальные преимущества над ConsoleFramework? Может, если библиотека развивается медленно, стоило начать с пулл-реквестов, а не с отдельной реализации конкурента с нуля? :)


        1. zawodskoj
          12.07.2016 15:59

          Когда я начинал разработку, про эту библиотеку я не знал
          Принципиальных отличий нет, но реализовано все по-другому. Начиная от реализации кроссплатформенности (хотя есть свои косяки), заканчивая недавно добавленной поддержкой XAML (в библиотеке elw00d самописные парсеры, у меня System.Xaml)


          1. Athari
            12.07.2016 16:48

            Посмотрел код. С лейаутом всё очень печально (в WPF и ConsoleFramework двухпроходной measure-arrange, у вас что-то непонятное), типографики нет (перенос текста по дефисам и всё такое), иерархия классов вызывает вопросы (зачем GridWindow, если есть Grid и Window?), код местами очень сомнительный (простыни пятивложенного кода на несколько страниц в Grid). В целом, всё несоизмеримо проще и топорнее, чем в ConsoleFramework. По-моему, лучше приложить усилия к развитию ConsoleFramework, чем изобретать что-то своё.


            У System.Xaml есть серьёзный недостаток — он не очень-то переносимый и универсальный: его нет в .NET Core, а в Mono он кривой.


            1. zawodskoj
              12.07.2016 17:07

              Бросать разработку я не буду, но в ConsoleFramework пару пулл-реквестов может быть и сделаю


    1. zawodskoj
      06.07.2016 15:18

      Кроссплатформенность сделана отвратительно


      1. elw00d
        06.07.2016 18:07

        Что же вам не понравилось?


        1. zawodskoj
          06.07.2016 19:05
          +1

          Смешан код под винду и под ncurses


          1. elw00d
            06.07.2016 20:57
            +1

            А мне норм ) Проблем с этим не испытывал. Но от хорошего pull request'а не откажусь


  1. roboter
    06.07.2016 15:35
    +2

    https://github.com/kristopolous/BOOTSTRA.386 для веба :)


  1. Shoomaher
    06.07.2016 19:23

    Боюсь, что задаю глупый вопрос, но всё же, есть ли что-нибудь подобное для java? Хоть что-нибудь, что поможет реализовать псевдо-графический интерфейс?


    1. korolv
      06.07.2016 22:18
      +2

      Мы Lanterna используем для Java. Вполне удобная библиотека: github.com/mabe02/lanterna


      1. Shoomaher
        07.07.2016 10:54

        Спасибо большое!


  1. sova
    07.07.2016 02:46

    чем оно лучше curses?)


    1. zawodskoj
      07.07.2016 07:26

      curses — библиотека для управления терминалом. Не надо сравнивать мою библиотеку и curses — у них разное назначение


      1. sova
        07.07.2016 14:14
        -1

        но curses позволяет делать все тоже самое…


        1. zawodskoj
          07.07.2016 15:27
          +1

          Зачем тогда WPF? WinAPI ведь позволяет делать все то же самое


          1. sova
            07.07.2016 15:29

            не совсем корректно, curses позволяет делать тоже самое для консоли примерно в тех же терминах.
            просто более известный проект.


            1. zawodskoj
              07.07.2016 15:35

              Во-первых curses нет под Windows (если не считать порты вроде PDCurses, последний стабильный релиз которого был в 2008)
              Во-вторых в curses нет и половины того функционала, который есть или будет в моей библиотеке (Data Binding, XAML), ибо предназначена она не для этого
              В-третьих, curses не нативен для c# — нужно писать обертки для него (CursesSharp, например)


            1. zawodskoj
              07.07.2016 16:03

              Плюс к этому, curses и ООП — вещи несовместимые. Опять же, нужно оборачивать.
              Ну или можно не оборачивать и писать вот так


  1. qwertEHOK
    07.07.2016 11:02

    а под VCL (Delphi) нет такого?
    У заказчиков WinXP и любое GUI приложение под Delphi XE10 требует дополнительного тестирования. Проще им сделать отдельный инфтерфейс в стиле DOS


  1. DrugGarry
    07.07.2016 13:03

    Был Visual Basic For DOS 1.0, дальше не пошло. Окошки в стиле Борландовского Турбо. Ээех, время бежит…