Графический интерфейс пользователя

Как использовать десктоп без десктопа? Обзор Samsung DeX

Tutorial

Привет, Хабр.
Как и у многих разработчиков, периодически работающих дома, у меня есть достаточно мощный десктоп, которого без проблем хватает для разных задач. Но периодически бывают дела вроде написания этой статьи для Хабра, где большой вычислительной мощности не нужно, но при этом хочется сидеть за любимым большим монитором и клавиатурой.
Решение пришло случайно при просмотре одного из обзоров — интерфейс Samsung DeX, позволяющий использовать в десктоп-режиме собственный смартфон.
Данная статья набрана и сверстана на смартфоне. Для тех кому интересно, как это работает, продолжение под катом.

Как работает GUI-приложение

Что ещё может происходить в UI-цикле? Если нам надо переместить окно на рабочем столе или сменить текст в лейбле, добавить дочерний элемент, можем ли мы сделать это во время отрисовки? Очевидно, эти операции могут быть небезопасными. Например, можно добавить элемент в массив childs  в тот момент, когда он находится в процессе перечисления, что вызовет ошибку. И это не единственное тонкое место — изменение размеров элементов, текста, цвета и других параметров во время отрисовки могут создать проблемы в коде рендера.

Правильным решением здесь будет синхронизация процесса рендера и модификации параметров элементов интерфейса. Поскольку подобные операции (назовём их invoke) в GUI происходят довольно часто, хорошим решением будет просто выполнять их в том же потоке, что и рендер, непосредственно перед ним. Для этого сделаем очередь операций и выберем метод добавления операции в очередь (invokeLater).

Программист, который хочет провести модификацию иерархии/параметров элементов, должен делать это только внутри таких операций. Кроме того, события ввода (например, с мыши и клавиатуры) также должны обрабатываться в этой очереди. Теперь мы имеем представление о том, как работает GUI-приложение.

Графический интерфейс пользователя

За пределами приложения лежат устройства ввода-вывода, которые симулированы  классами из пакета by.dev.gui.driver, а «виртуальной машиной» является простой JFrame, который получает от «видеоустройства» картинку (Image) и посылает события мыши в соответствующее «устройство» ввода.

Монитор представляет собой буфер пикселей, в который и рисуется интерфейс, а в конце каждого UI-цикла созданная им видеостраница посылается на «матрицу».

Для управления буфером пикселей создан класс Texture. Ещё вы могли заметить, что GraphicsContext потерял свойство offset и теперь всегда рисует в текстуру, начиная с верхнего левого угла (это изменение будет объяснено ниже при рассмотрении алгоритмов полупрозрачности), у него появился метод fill() для монохромной заливки прямоугольной области, а также наследник SafeGraphicsContext. Дело в том, что дочерние элементы зачастую могут выходить за границы своих родителей, следовательно, их пиксели могут отрисоваться в несуществующие области текстуры. Чтобы не производить проверку попадания в границы родителя каждый раз, проще всего делать её на стороне графического контекста.

Барабанная дробь! Вот мы и создали все инструменты, чтобы всё вышесказанное обрело хоть какой-то практический смысл.

Основные функции GUI

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

Функция Описание
GUICreate Создание окна.
GUICtrlCreate… Создание различных элементов управления в окне.
GUISetState Отображает или скрывает окно.
GUIGetMsg Опрос GUI, чтобы обнаружить, если событие произошло (Только в режиме цикла)
GUICtrlRead Чтение данных из элемента управления.
GUICtrlSetData Установить/изменить данные в элементе управления.
GUICtrlUpdate… Изменение различных параметров элементов управления (цвет, стиль и т.д.)

Необходимо в скрипт добавить строку #include <GUIConstantsEx.au3> для подключения основных констант связанных с созданием GUI. Есть другие файлы, содержащие константы, связанные с различными элементами управления для создания их в GUI.

Сначала давайте создадим окно, назовем его «Привет Мир» и сделаем его размером 200 на 100 пиксель. При создании нового окна, оно скрыто, поэтому мы должны отобразить его.

#include <GUIConstantsEx.au3>
GUICreate(«Привет Мир», 200, 100)
GUISetState()
Sleep(2000)

Если выполнить приведённый выше пример, вы увидите открытие окна и закрытие через 2 секунды. Это не очень интересно … давайте добавим немного текста и кнопку ОК. Текст будет добавлен в координаты x=30, y=10 и кнопка в координаты x=70, y=50 и шириной 60 пикселей.

#include <GUIConstantsEx.au3>
GUICreate(«Привет Мир», 200, 100)
GUICtrlCreateLabel(«Привет Мир! Как дела?», 30, 10)
GUICtrlCreateButton(«OK», 70, 50, 60)
GUISetState()
Sleep(2000)

Теперь на много лучше, но как сделать реакцию GUI на нажатие кнопки? Здесь мы должны принять решение, как обрабатывать события — через MessageLoop (цикл опроса GUI) или через функции OnEvent (по событию).

Как можно реализовать drag-n-drop для окон?

Речь идёт о механизме перетаскивания окна зажатием мыши на его заголовке. Допустим, событие нажатия мыши происходит над заголовком конкретного окна. Окно запоминает, что его в данный момент «тянут» и ждёт событий перемещения мыши и отжатия кнопки. Однако эти события дойдут до окна только в том случае, если пользователь перемещает мышь исключительно в пределах элемента, отвечающего на это событие, то есть заголовка окна. Если же мышь выйдет за его пределы, то nodeForMouseEvent уже не найдёт его как получатель события, и перемещение окна прекратится. Более того, если окно не получит события отпускания кнопки мыши, оно так и останется навсегда в режиме перетаскивания.

По теме

  • Колонка Ограниченные, зависимые, тривиальные — с проблемами. Десять причин не использовать чужие библиотеки

  • Как научиться программировать с нуля и найти первую работу. Большой FAQ от Reddit

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

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

Можно придумать несколько таких механизмов, но для реализации нашей задачи (событие кнопки при отпускании мыши и перетаскивании окон) можно обойтись малой кровью — подходом с запоминанием активного элемента. Это элемент, который в данный момент эксклюзивно отвечает на события мыши. Пока он активен, рабочий стол будет направлять события исключительно ему, независимо от того, находится ли мышь над элементом или элемент в границах своего родителя. Пока активного элемента нет, рабочий стол будет предлагать событие элементу под курсором, вызывая метод doMouseEvent(). Метод должен возвращать boolean, который говорит, готов ли элемент стать активным. Как только один из элементов вернёт true, он станет активным и будет перехватывать все события мыши. Продолжаться это будет до тер пор, пока doMouseEvent() не вернёт false, что означает — элемент более не активен, и все другие опять могут получать события мыши. Этого простого и немного костыльного подхода хватит, чтобы удовлетворить наши потребности. 

Графический интерфейс пользователяГрафический интерфейс пользователя

Харизматичный дизайн или использование эмпатии для вовлечения пользователя

Все больше нарастает тенденция компаний и сервисов иметь в своем вооружении не просто функциональный сайт, выполняющий задачи, а эстетически приятный глазу продукт, имеющий приятный дизайн. Не так давно сайт с качественно проработанным UI/UX был уже преимуществом и выделялся среди конкурентной массы компаний. На данный момент таким обзавелись практически все, меняется только оформление, которым уже тоже достаточно сложно удивить пользователя. Хотя этот аспект затрагивает больше область маркетинга чем дизайна, пробиться к сознанию пользователя становится все сложней, поэтому данная область обязательна к изучению еще и дизайнерами.

Концепция GUI

GUI состоит из одного или нескольких окон и каждое окно содержит один или несколько элементов управления. GUI управляем событиями, которые означают реагирование на событие, подобно реакции на нажатие кнопки. Скрипт тратит большую часть времени на бездействие и ожидание события — это мало чем отличается от обычного скрипта, где вы управляете его поведением, устанавливая что и где должно произойти! Представьте это как ожидание почтальона у дверей — вы ожидаете пока письмо не появится в почтовом ящике и затем вы смотрите на письмо и решаете что с ним делать — это аналогично работе GUI — вы ожидаете прихода почтальона.

Конечно, вы можете выбрать другие задачи, в то время как GUI активен — например вы можете использовать функции GUI для создания сложного окна прогресса, которое обновляется, пока скрипт выполняет набор действий.

Прочее

Также Хансельман с коллегами показали некоторые вещи, которые вообще-то уже были анонсированы ранее, но трансляция позволяла увидеть их в действии — особенно наглядно в таком варианте выглядят GitHub Codespaces, представленные недавно на GitHub Connect.

Если совсем коротко, то Codespaces — это «мы встроили VS Code прямо вам в GitHub». Но есть интересные нюансы: с одной стороны, тут можно подтягивать ваши настройки десктопного VS Code (создавая вам максимально привычное окружение), а с другой стороны, при этом всё подстраивается под зависимости конкретного репозитория (так что не нужно устанавливать на свой компьютер кучу вещей только для того, чтобы чуть-чуть поконтрибьютить). И ещё к сессии Codespaces можно подключиться из десктопного VS Code — если в процессе вы поняли, что в браузере всё-таки некомфортно, сможете продолжать не в нём. Пока что вся эта красота в ограниченной бете, можно запросить ранний доступ.

Другая ранее уже представленная штука, о которой вспомнили — новый Surface Book 3. Тут похвастались тем, что у него до 32 гигабайт оперативной памяти, SSD до двух терабайт, интеловские процессоры 10-го поколения — в общем, разработчикам подходит.

И немного поговорили о том, как с помощью Xamarin можно делать мобильные приложения для устройств с двумя экранами (напомним, Microsoft такие устройства сейчас готовит).

А, ну и Windows Terminal добрался до версии 1.0 — никаких суперфич при этом не добавилось, но теперь он официально «production-ready». О нём на Хабре есть отдельный пост непосредственно от Microsoft.

Ещё на Build были анонсы вне этой презентации, но менее релевантные для жизни обычного разработчика — от того, что Microsoft сделали новый суперкомпьютер, до приложения Lists (выглядит как потомство todo-менеджера и Excel).

VR-нейроинтерфейс для людей с Альцгеймером

Из песочницы

Представьте, что вы играете в увлекательную компьютерную игру, набираете полезные скиллы, проходите новые уровни, изучаете карты игры, получаете награды, а на следующий день заходите в игру снова, но вот часть скиллов потеряна, уровни нужно проходить заново, карты уже изменились и часть наград отобрали. Вы восстанавливаете утраченные достижения, продвигаетесь немного дальше, а на следующий день снова откатываетесь назад. И так каждый раз. И более того, постепенно ваши откаты превышают продвижение вперед — в конце концов вы уже находитесь в самом начале, не помните, что проходили, и даже не знаете, как играть. Примерно так происходит реальная жизнь у людей с диагнозом «Болезнь Альцгеймера» (БА).

Вкратце про болезнь Альцгеймера

Это нейродегенеративное заболевание, характеризующееся когнитивными нарушениями, развитием деменции, социальной дезадаптацией, сокращением продолжительности жизни. Патофизиологические изменения, характерные для БА, начинаются за годы и даже за десятилетия до клинического подтверждения заболевания. Кадр из фильма «Дневник памяти»
Болезни в большей степени подвержены люди пожилого возраста, хотя в редких случаях она может проявляться и сильно раньше. Причем чем дальше за 60, тем больше вероятность развития заболевания. Наверно, поэтому существует распространенное мнение, что Альцгеймер придет к каждому, просто не каждый до него доживет.

[Как работает обработчик]

Если вам не интересно как, смело пропускайте данный раздел =)

Что же тут произошло? А произошло тут создание функции (то есть Visual Studio за нас написала код, нам никто не мешает его ручками писать) с сигнатурой обработчика системного события. У функции два аргумента:

  • object sender – объект от которого пришло событие, в нашем случае это будет кнопка button1
  • EventArgs e – специфически свойства события, в клика нет особых свойства, а вот всякие события типа клика мыши или нажатия кнопки могут содержать дополнительную информацию (см. выше про системные события)

Далее студия привязала данную функцию к кнопке. Если смотреть через интерфейс (переключимся на форму нажав Shift+F7), то эта функция будет указана в качестве значения свойства Click в разделе Событий.

Графический интерфейс пользователя

Если же смотреть еще глубже можно открыть, автогенерируемый файлик для формы Form1.Designer.cs

Графический интерфейс пользователя

Там мы увидим код:

Графический интерфейс пользователя

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

но ладно, вернемся к нашему обработчику.

Concurrent Mode в React: адаптируем веб-приложения под устройства и скорость интернета

В этой статье я расскажу о конкурентном режиме в React. Разберёмся, что это: какие есть особенности, какие новые инструменты появились и как с их помощью оптимизировать работу веб-приложений, чтобы у пользователей всё летало. Конкурентный режим — новая фишка в React. Его задача — адаптировать приложение к разным устройствам и скорости сети. Пока что Concurrent Mode — эксперимент, который может быть изменён разработчиками библиотеки, а значит, новых инструментов нет в стейбле. Я вас предупредил, а теперь — поехали.
Сейчас для отрисовки компонентов есть два ограничения: мощность процессора и скорость передачи данных по сети. Когда требуется что-то показать пользователю, текущая версия React пытается отрисовать каждый компонент от начала и до конца

Неважно, что интерфейс может зависнуть на несколько секунд. Такая же история с передачей данных

React будет ждать абсолютно все необходимые компоненту данные, вместо того чтобы рисовать его по частям.
Конкурентный режим решает перечисленные проблемы. С ним React может приостанавливать, приоритизировать и даже отменять операции, которые раньше были блокирующими, поэтому в конкурентном режиме можно начинать отрисовывать компоненты независимо от того, были ли получены все данные или только часть.

Добавляем поля для ввода

На форму надо чего-то добавить. По задаче у нас два параметра, значит придется добавить два поля для ввода. Откроем панель с элементами и для удобства зафиксируем ее с помощью пипки в верхнем правом углу.

Графический интерфейс пользователя

Если у вас вдруг не видно панели с элементами, включите ее через пункт меню Вид/Панель элементов

Теперь добавим элементы на форму, нам потребуется два элемента вида TextBox (поля для ввода текста)

Графический интерфейс пользователя

Чтобы было понятно чего в них вводить добавим подписи (элементы типа Label)

Графический интерфейс пользователя

Но у этих подписей вместо текста написано label1 и label2, поменяем их свойства. У всех элементов типа Label есть свойство Text,
которое определяет чего в них писать. Выделим label1 кликнув на него, он обведется пунктирной рамкой

в правом нижнем углу найдем панель свойств (если ее не видно нажмите F4). Среди множества свойств найдем то что называется Text
и введем в него корректный текст.

Графический интерфейс пользователя

Закончив вводить переключимся на форму, кликнув на нее, если все было сделано корректно текст label1 заменится на руб. заработал Петров

Повторим ту же процедуру для label2

  • выберем на форме
  • в окне свойств в поле Text введем руб. заработал Иванов
  • снова переключимся на форму

получим:

RecyclerView.ItemDecoration: используем по максимуму

Привет, дорогой читатель Хабра. Меня зовут Олег Жило, последние 4 года я Android-разработчик в Surf. За это время я поучаствовал в разного рода крутых проектах, но и с легаси-кодом поработать довелось.
У этих проектов есть как минимум одна общая деталь: везде есть список с элементами. Например, список контактов телефонной книги или список настроек вашего профиля.
В наших проектах для списков используется RecyclerView. Я не буду рассказывать, как писать Adapter для RecyclerView или как правильно обновлять данные в списке

В своей статье расскажу о другом важном и часто игнорируемом компоненте — RecyclerView.ItemDecoration, покажу как его применить при вёрстке списка и на что он способен

Графические интерфейсы

Родная среда обитания Git — это терминал.
Новые фунции изначально доступны только там и лишь терминал поможет вам полностью контролировать всю мощь Git.
Но текстовый интерфейс — не лучший выбор для всех задач; иногда графическое представление более предпочтительно, а некоторые пользователи чувствуют себя комфортней, орудуя мышкой.

Также стоит понимать, что разные интерфейсы служат разным целям.
Некоторые Git клиенты ограничиваются лишь той функциональностью, которую их автор считает наиболее востребованной или эффективной.
Учитывая это, ни один из представленных ниже инструментов не может быть «лучше» остальных: они просто предназначены для решения разных задач.
Также стоит помнить, что всё, что можно сделать с помощью графического интерфейса, может быть выполнено и из консоли; командная строка по прежнему является местом, где у вас больше всего возможностей и контроля над вашими репозиториями.

и

Установив Git, вы также получаете два графических инструмента: и .

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

Проще всего вызвать Gitk из командной строки:
Просто перейдите в директорию с репозиторием и наберите:

Gitk принимает много различных опций, большинство из которых транслируются в используемый .
Возможно, наиболее полезная опция — , которая указывает Gitk выводить коммиты, доступные из любой ссылки, а не только HEAD.
Интерфейс Gitk выглядит так:

Графический интерфейс пользователя
Рисунок 152. — инструмент для просмотра истории

Интерфейс на картинке похож на вывод ; каждая точка соответствует коммиту, линии отражают родство коммитов, а ссылки изображены цветными прямоугольниками.
Жёлтая точка обозначает HEAD, а красная — изменения, которые попадут в следующий коммит.
В нижней части расположены элементы интерфейса для просмотра выделенного коммита: слева показаны изменения и комментарий, а справа — общая информация по изменённым файлам.
В центре расположены элементы для поиска по истории.

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

И его интерфейс выглядит так:

Графический интерфейс пользователя
Рисунок 153.  — инструмент редактирования коммитов

Слева находится область редактирования Git индекса: изменения в рабочей директории наверху, добавленные в индекс изменения — снизу.
Вы можете перемещать файлы целиком между двумя состояниями, кликая на иконки, или же вы можете просмотреть изменения в конкретном файле, кликнув по нему.

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

Справа снизу находится область для ввода сообщения коммита и несколько кнопок.
Введите сообщение и нажмите кнопку «Commit» чтобы выполнить коммит.
Также можно изменить предыдущий коммит, выбрав радиокнопку «Amend», что приведёт к обновлению индекса содержимым предыдущего коммита.
После этого вы можете как обычно добавлять или удалять файлы из индекса, изменить сообщение коммита и, нажав кнопку «Commit» создать новый коммит, заменив им предыдущий.

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

Другие инструменты

Существует огромное множество других графических инструментов для работы с Git, начиная от специализированных, выполняющих одну задачу, заканчивая «комбайнами» покрывающими всю функциональность Git.
На официальном сайте Git поддерживается в актуальном состоянии список наиболее популярных оболочек: http://git-scm.com/downloads/guis.
Более подробный список доступен на Git вики: .

prev | next

Обработка ошибок

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

Графический интерфейс пользователя

появление ее закономерно, программа пытается с помощью метода int.Parse преобразовать строку в число, но в строке пусто и преобразовывать нечего.
Аналогичная ошибка появится если ввести буквы вместо цифр.

Наверное было бы здорово, просто проигнорировать нажатие кнопки с некорректными данными, для этого нам надо заставить программу не падать.
Делается это не сильно сложно, путем добавления конструкции для перехвата ошибок, Именуется она try-catch, и выглядит так:

правда если просто вставить код в таком виде то он будет ругаться на переменные ivanovSum и petrovSum, после блока try/catch.
Это происходит потому что переменные инициализируются внутри блока try, надо их вынести вовне. Придется указать тип явно.

проверяем:

Графический интерфейс пользователя

Красота! Можно сообщение выдавать об ошибке (но лучше не надо):

получится:

Графический интерфейс пользователя

Это в принципе должно хватить для выполнения первого задания в лабе 4.

PowerToys Run

Первое, что показали — вроде бы мелочь, но вероятно, некоторые будут пользоваться ей активнее всего остального представленного. В наборе утилит PowerToys появился новый инструмент PowerToys Run, что-то вроде «Win+R на максималках». По нажатию Alt+Space на экране появляется крупная поисковая строка, позволяющая открывать приложения, файлы и папки.

Выглядит это похоже на Spotlight из macOS:

Но в PowerToys Run, если начать ввод с символа >, можно ввести консольную команду и сразу её выполнить. На Mac так умеет стороннее приложение Alfred, но не стандартный Spotlight.

Утилита входит в новый релиз PowerToys v0.18.0, его можно брать на GitHub.

Режимы опроса событий GUI

Как было сказано выше есть два основных режима GUI: MessageLoop (цикл опроса GUI) и OnEvent (по событию). Это просто два разных способа реагирования на событие GUI. Выбранный режим зависит от личных предпочтений, и в некоторой степени от типа GUI. Оба режима в равной степени способны создать любой GUI, но иногда один режим лучше другого подходит для задачи.

По умолчанию используется режим MessageLoop (цикл опроса GUI). Чтобы переключиться в режим OnEvent используйте .

Режим MessageLoop (цикл опроса GUI, по умолчанию)

В режиме MessageLoop ваш скрипт большую часть своего времени будет тратить в цикле. Этот цикл просто опрашивает GUI используя функцию GUIGetMsg. Когда произошло событие, функция GUIGetMsg возвращает значение (нажатие кнопки, закрытие GUI, и т.д.).

В этом режиме вы получаете сообщения только в случае активного опроса элементов управления функцией GUIGetMsg, таким образом вы должны убедится, что вызываете функцию довольно часто (более 20-ти раз в секунду), иначе ваш GUI не будет откликаться на взаимодействие с элементами управления.

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

Смотрите страницу MessageLoop для более подробного понимания этого режима.

Режим OnEvent (по событию)

В режиме OnEvent (по событию) опрос GUI выполняется на уровне интерпретатора. При возникновении события выполняется временная приостановка скрипта и вызов назначенной функции связанной с определённым элементом управления. Например, если пользователь нажимает кнопку Button1, GUI приостанавливает основной скрипт и вызывает ранее определенную пользователем функцию связанную с Button1. После выполнения функции приостановленный основной скрипт возобновляет работу. Этот режим аналогичен методу формы в Visual Basic.

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

Смотрите страницу OnEvent для более подробного понимания этого режима.

История

Благодаря исследованиям, проведённым в 1960-е годы Дагом Энгельбартом в научно-исследовательском институте Стэнфорда, был изобретён графический интерфейс пользователя.

Впоследствии концепция GUI была перенята учёными из исследовательской лаборатории Xerox PARC в 1970-х. В 1973 году в лаборатории Xerox PARC собрали молодых учёных и дали свободу исследований. В результате, кроме всего прочего, на свет появляется концепция графического интерфейса WIMP (Windows, Icons, Menus, Pointers) и в рамках этой концепции создаётся компьютер Alto. Он не был выпущен как коммерческий продукт, но широко использовался на фирме как корпоративный инструмент Xerox.

В 1979 году Three Rivers Computer Corporation выпустила рабочую станцию PERQ, похожую по принципам построения на Alto. В 1981 году Xerox выпустила продолжение Alto — .

Коммерческое воплощение концепция GUI получила в 1984 году в продуктах корпорации Apple Computer. Apple критиковали за отказ от командной строки в пользу графического интерфейса.
В 1985 году операционной GUI с многозадачностью был использован в системе AmigaOS.

Позднее GUI стала стандартной составляющей большинства доступных на рынке операционных систем и приложений. Примеры систем, использующих GUI: Mac OS, GEM, Atari TOS, Microsoft Windows, Solaris, GNU/Linux, NeXTSTEP, OS/2, BeOS, Android, iOS, Bada, MeeGo.

Хотя в подавляющем большинстве систем GUI является надстройкой для операционной системы, существуют и независимые его реализации. Известен вариант графической программы BIOS Setup, когда ещё до загрузки ОС управление настройками IBM PC-совместимой ЭВМ производится мышью, аналогично полноценному GUI. Также имеются GUI для МК, не требующие ОС.

Основные десктопные accessibility технологии

Старый добрый Win32 API

Большинство Windows приложений, написанных до выхода WPF и затем Windows Store, построены так или иначе на Win32 API. А именно, MFC, WTL, C++ Builder, Delphi, VB6 — все эти инструменты используют Win32 API. Даже Windows Forms — в значительной степени Win32 API совместимые.

Инструменты: AutoIt (похож на VB) и Python обертка pyautoit, AutoHotkey (собственный язык, есть IDispatch COM интерфейс), pywinauto (Python), RAutomation (Ruby), win32-autogui (Ruby).

Microsoft UI Automation

Главный плюс: технология MS UI Automation поддерживает подавляющее большинство GUI приложений на Windows за редкими исключениями. Проблема: она не сильно легче в изучении, чем Win32 API. Иначе никто бы не делал оберток над ней.

Фактически это набор custom COM интерфейсов (в основном, UIAutomationCore.dll), а также имеет .NET оболочку в виде . Она, кстати, имеет привнесенный баг, из-за которого некоторые UI элементы могут быть пропущены. Поэтому лучше использовать UIAutomationCore.dll напрямую (если слышали про UiaComWrapper на C#, то это оно).

Разновидности COM интерфейсов:

(1) Базовый IUknown — «the root of all evil». Самый низкоуровневый, ни разу не user-friendly.
(2) IDispatch и производные (например, ), которые можно использовать в Python с помощью пакета win32com.client (входит в pyWin32). Самый удобный и красивый вариант.
(3) Custom интерфейсы, с которыми умеет работать сторонний Python пакет comtypes.

Инструменты: TestStack.White на C#, pywinauto 0.6.0+, Winium.Desktop на C#, Python-UIAutomation-for-Windows (у них исходный код сишных оберток над UIAutomationCore.dll не раскрыт), RAutomation на Ruby.

AT-SPI

Несмотря на то, что почти все оси семейства Linux построены на X Window System (в Fedora 25 «иксы» поменяли на Wayland), «иксы» позволяют оперировать только окнами верхнего уровня и мышью/клавиатурой. Для детального разбора по кнопкам, лист боксам и так далее — существует технология AT-SPI. У самых популярных оконных менеджеров есть так называемый AT-SPI registry демон, который и обеспечивает для приложений автоматизируемый GUI (как минимум поддерживаются Qt и GTK).

Инструменты: pyatspi2.

pyatspi2, на мой взгляд, содержит слишком много зависимостей типа того же PyGObject. Сама технология доступна в виде обычной динамической библиотеки . К ней имеется Reference Manual. Для библиотеки pywinauto планируем реализовать поддержку AT-SPI имеено так: через загрузку libatspi.so и модуль ctypes. Есть небольшая проблема только в использовании нужной версии, ведь для GTK+ и Qt приложений они немного разные. Вероятный выпуск pywinauto 0.7.0 с полноценной поддержкой Linux можно ожидать в первой половине 2018-го.

Apple Accessibility API

На MacOS есть собственный язык автоматизации AppleScript. Для реализации чего-то подобного на Python, разумеется, нужно использовать функции из ObjectiveC. Начиная, кажется, еще с MacOS 10.6 в предустановленный питон включается пакет pyobjc. Это также облегчит список зависимостей для будущей поддержки в pywinauto.

Инструменты: Кроме языка Apple Script, стоит обратить внимание на ATOMac, он же pyatom. Он совместим по интерфейсу с LDTP, но также является самостоятельной библиотекой

На нем есть пример автоматизации iTunes на macOs, написанный моим студентом. Есть известная проблема: не работают гибкие тайминги (методы ). Но, в целом, неплохая вещь.

Элементы управления GUI

Все пользователи знакомы с элементами управления, нажимая их или взаимодействуя с типами элементов управления окна. Типы элементов управления, создаваемые с помощью AutoIt перечислены ниже — большинство их вы уже использовали в других программах имеющих GUI-окно.

Label Обычный текст.
Button Обычная кнопка.
Input Однострочный элемент, в который вы можете вводить текст.
Edit Многострочный элемент, в который вы можете вводить текст.
Checkbox Квадрат с «галочкой» или «без галочки».
Radio Кнопка-переключатель — только один из нескольких может быть отмечен.
Combo Раскрывающийся список.
List Список.
Date Выбор даты.
Pic Рисунок.
Icon иконка (значок).
Progress Полоса прогресса.
Tab Вкладки. Для создания элементов управления на вкладках.
UpDown Элемент управления, который может быть добавлен в input.
Avi Отображает видео клип в формате AVI.
Menu Меню в верхней части окна.
ContextMenu Контекстное меню, которое появляется при клике правой кнопкой мыши в окне.
TreeView Элемент управления аналогичный дереву эксплорера.
Slider Элемент управления аналогичный регулятору громкости звука.
ListView Элемент управления, отображающий информацию в виде таблицы.
ListViewItem Пункты в ListView.
Graphic Графический элемент (фигуры) отрисованный с помощью GUICtrlSetGraphic.
Dummy Пустышка, элемент не отображается в окне, но реагирует на событие.

Вот пример одного GUI окна, которое содержит многие доступные элементы управления. Как вы видите, можно создавать очень детальные GUI!

Элементы управления создаются с помощью функций GUICtrlCreate….  При создании элементов управления возвращается идентификатор (ID).  Наиболее важные понятия об идентификаторе (ID) необходимо иметь в виду, это:

Идентификатор элемента управления является положительным числом (то есть число, большее 0)
Каждый идентификатор элемента управления уникален — даже когда есть несколько окон
Идентификатор элемента управления — это тоже значение, что и значение возвращаемое с помощью AutoIt Window Info Tool .

Новое CSS-свойство content-visibility ускоряет отрисовку страницы в несколько раз

Recovery Mode

5 августа 2020 разработчики Google анонсировали новое CSS-свойство в версии Chromium 85. Оно должно существенно повлиять на скорость первой загрузки и первой отрисовки на сайте; причём с только что отрендеренным контентом можно взаимодействовать сразу же, не дожидаясь загрузки остального содержимого. заставляет юзер-агент пропускать разметку и покраску элементов, не находящихся на экране. По сути, это работает как lazy-load, только не на загрузке ресурсов, а на их отрисовке.В этой демке , применённый к разбитому на части контенту, даёт прирост скорости рендера в 7 раз

Пакетный менеджер winget

В трансляции сразу же показали наглядный пример команды, которую удобно использовать из строки PowerToys Run: «winget install что-то». Да, у Windows появляется свой официальный пакетный менеджер! Чтобы, например, на новую машину можно было накатывать целый набор софта одним простым скриптом.

Мы не ограничились просмотром трансляции, а почитали на Hacker News реакцию разработчиков. Она оказалась различной. Есть точка зрения «слушайте, но эта штука просто скачивает и запускает exe-файлы, у неё нет ни управления зависимостями, ни даже функции удаления». На это возражают «В планы добавить всё есть, да и сильно ли нужно в Windows это управление зависимостями».

Сейчас winget в превью-версии. Он доступен в Microsoft Store тем, кто участвует в Insider-программе, и компания рекомендует именно этот способ установки, позволяющий автоматически получать из Store апдейты. Но код выложен на GitHub, и никто не запрещает собрать его самостоятельно, лишаясь автоматических апдейтов.

Еще пара скриншотов

Демо DlangUI — Tetris

dmd

Widgets & Layouts

  • TextWidget — текст
  • Button — кнопка с текстом
  • ImageButton — кнопка с картинкой
  • ImageTextButton — кнопка с картинкой и текстом
  • CheckBox — понятно из названия
  • RadioButton — понятно из названия
  • ImageWidget — картинка
  • EditLine — однострочный редактор
  • ComboBox — комбобокс — для выбора элемента из выпадающего списка
  • VerticalLayout — расположить вложенные виджеты по вертикали
  • HorizontalLayout — расположить вложенные виджеты по вертикали
  • TableLayout — расположить вложенные виджеты в несколько столбцов, как в таблице

Обработка сигналов (событий) от виджетов

  • onCheckChangeListener — состояние checked изменено (например, для CheckBox, RadioButton)
  • onFocusChangeListener — изменено состояние фокуса этого виджета
  • onKeyListener — перехват событий от клавиатуры
  • onMouseListener — перехват событий мыши

Часто используемые свойства виджета

  • margins — отступ от соседних виджетов или границ контейнера (фон виджета рисуется с отступом на margins)
  • padding — отступ от границ виджета до его внутренних элементов
  • backgroundColor — цвет фона (32 bit uint, 0xAARRGGBB)
  • backgroundImageId — фоновое изображение — id ресурса
  • textColor — цвет текста (32 bit uint, 0xAARRGGBB)
  • fontSize — размер шрифта

Android

Другие полезные виджеты

  • EditBox — многострочный редактор
  • TreeWidget — дерево
  • StringGrid — таблица, похожая на Excel
  • TabWidget — табы — для выбора страниц
  • AppFrame — базовый класс основного виджета окна с меню, тулбарами и стстус-строкой, для удобства написания таких приложений.
  • ScrollBar
  • ToolBar
  • StatusLine
  • ScrollWidget — реализует скроллинг вложенного в него виджета, если размеры превышают доступное место
  • DockHost, DockWidget — для приложений с док-виджетами по краям от основного виджета окна (как в IDE)

Ссылки

  • Страница проекта на GitHub
  • Онлайн — документация
  • Багтрекер
  • Скриншоты
  • Страница проекта DlangIDE на GitHub
  • Чат в Gitter