Перейти к содержимому
ГоМастер

Поиск по урокам

Найдите урок, курс, термин или раздел

Урок 1 из 25 ~15 мин +50 XP

Знакомство с Fyne: GUI на Go

Что такое Fyne и почему именно он, если в Go захотелось окна с кнопками? Fyne — самый заметный GUI-тулкит языка: виджеты, компоновка и тема написаны на чистом Go, рендер идёт через OpenGL, а одна кодовая база собирается под Windows, macOS, Linux, iOS, Android и даже браузер. Дебютный урок курса: архитектура тулкита, модель CanvasObject и виджетов, платформы сборки и честное сравнение с Walk и Gio.

Содержание урока · 15 разделов

Начнём с ситуации, в которой рано или поздно оказывается каждый Go-разработчик. Вы написали утилиту: логика аккуратная, логи красивые, конфиг читается из файла — и всё хорошо, пока заказчик не говорит: а можно не в терминале, а окошком с кнопкой? В экосистеме Python или C# на этот вопрос есть ответ по умолчанию. В Go — нет: GUI считается известным слабым местом языка, стандартная библиотека не содержит ничего интерфейсного, и дальше начинается выбор из доброго десятка библиотек. Вот здесь и стоит разобраться, что такое Fyne и почему он стал первым ответом на запрос «GUI на Go». Первая мажорная версия 1.0 вышла в марте 2019 года, и с тех пор проект вырос в самый заметный тулкит ниши: крупная команда, каталог приложений на fyne.io, собственная конференция. Курс, который вы начали, — про него: 25 уроков от первого окна до менеджера задач с темами, привязкой данных и упаковкой в сторы.

Что такое Fyne: GUI-тулкит на чистом Go#

Если вычесть маркетинг, что такое Fyne технически? Это тулкит и app-API, написанные на Go: сами виджеты, контейнеры, компоновщики и тема — обычный Go-код, который можно открыть и читать, а не обёртка над Qt или GTK, как в предыдущих поколениях Go-GUI. Слово «чистый» требует одной честной оговорки: для сборки нужен C-компилятор и системные инструменты разработки, потому что вывод на экран идёт через cgo-привязки к OpenGL и библиотеке GLFW. Но весь код, с которым вы работаете как автор приложения, — Go. README формулирует назначение одной строкой: «easy-to-use UI toolkit and app API» для десктопа и мобильных из единой кодовой базы. Вторая мажорная версия с обновлённым API вышла в январе 2021-го, актуальная ветка — v2.8. Визуальный язык вдохновлён Material Design, с оговоркой самой документации: базовая плотность у Fyne другая, иконка высотой 18 соответствует 24 в материальном Android-приложении. Важное следствие подхода «рисуем всё сами»: на Windows, macOS и Linux приложение выглядит одинаково — и это не нативный вид каждой системы, а единая тема тулкита. Кому-то это минус, кому-то наоборот: дизайн перестаёт зависеть от версии ОС у пользователя.

Первая программа — hello world из README

GO
package main

import (
        "fyne.io/fyne/v2/app"
        "fyne.io/fyne/v2/container"
        "fyne.io/fyne/v2/widget"
)

func main() {
        // приложение: под ним сидит драйвер платформы
        myApp := app.New()

        // окно с заголовком
        window := myApp.NewWindow("Привет")

        // метка и кнопка - обычные виджеты
        hello := widget.NewLabel("Привет, Fyne!")
        window.SetContent(container.NewVBox(
                hello,
                widget.NewButton("Нажми меня", func() {
                        hello.SetText("Заработало!")
                }),
        ))

        // показать окно и запустить цикл событий
        window.ShowAndRun()
}

Импорт-пути fyne.io/fyne/v2/... — первое, к чему привыкаешь: корневой пакет задаёт типы, подпакеты app, container и widget — всё остальное. Программа из шести содержательных строк открывает окно с меткой и кнопкой, а клик меняет текст метки. Пока просто прочитайте её как текст; во втором уроке установим тулкит и запустим это локально.

Каркас программы: приложение, окно и цикл событий#

Разберём каркас по слоям. app.New() создаёт приложение: за ним стоит драйвер платформы, который умеет открывать окна, собирать ввод и рисовать; для мобильных и настроек есть вариант app.NewWithID с идентификатором. myApp.NewWindow("Заголовок") — окно, а window.SetContent(...) задаёт корневой объект содержимого. Самая важная строка — последняя: ShowAndRun() — сокращение для window.Show() и myApp.Run() подряд. Run запускает цикл событий, run loop: он принимает клики и нажатия клавиш, перерисовывает экран и не даёт программе завершиться. Документация формулирует два жёстких правила. Первое: Run вызывается ровно один раз — цикл в приложении один, повторный вызов приводит к ошибкам. Второе: управление после Run вы получите только когда приложение закроется, поэтому функции, написанные после него, выполнятся в самом конце жизни программы. App.Quit() прерывает работу, но только в десктопных средах — на мобильных такой возможности нет. А если Run никто не вызвал, setup-код доходит до конца main, и процесс завершается — об этом отдельное задание ниже.

Что напечатается и когда?

Прочитайте код и выберите, что он выведет:

package main

import (
        "fmt"

        "fyne.io/fyne/v2/app"
        "fyne.io/fyne/v2/widget"
)

func main() {
        myApp := app.New()
        window := myApp.NewWindow("Завершение")
        window.SetContent(widget.NewLabel("Работаем..."))
        window.ShowAndRun()
        tidyUp()
}

func tidyUp() {
        fmt.Println("Приложение закрыто")
}

CanvasObject и виджеты: анатомия интерфейса#

У каждого окна есть canvas — область рисования, доступ даёт window.Canvas(). Всё, что можно нарисовать, — от прямоугольника до кнопки — является реализацией интерфейса fyne.CanvasObject: у объекта есть размер, позиция, видимость и метод Refresh() для перерисовки. Примитивы — canvas.Rectangle, canvas.Circle, canvas.Line, canvas.Text, canvas.Image — живут в пакете canvas, и из них, по формулировке документации, собран весь тулкит. Виджеты — особый вид CanvasObject: fyne.Widget добавляет интерактивное поведение, а внешний вид вынесен в отдельный объект — WidgetRenderer. Разделение сознательное. API виджета описывает поведение и состояние (SetText, SetEnabled), рендер его не касается; когда состояние меняется, вызывается Refresh, и рендерер перерисовывает элемент по новому состоянию. Из этого следует неожиданно приятное свойство: приложение можно прогонять юнит-тестами в памяти, вообще не отрисовывая его на экран — для этого в пакете test есть SoftwarePainter и безоконный canvas. Widget и WidgetRenderer — интерфейсы, и на них держится вся система кастомных виджетов: как такие «контракты» проектируются на чистом Go, подробно разбирается в уроке 10-interfejsy продвинутого курса, а свой виджет мы соберём в восьмом уроке этого курса.

Компоновка: MinSize и контейнеры#

Виджеты в Fyne не решают сами, где им стоять. Они сообщают минимальный размер — MinSize — а расстановкой занимаются контейнеры с компоновками. container.NewVBox из hello world складывает элементы в колонку: каждый получает ширину самого широкого соседа и высоту не меньше своей минимальной; горизонтальный HBox работает так же, но в строку и с общей высотой. Дальше по списку пакета layout: Border с зонами сверху, слева, снизу и справа, где всё остальное занимает центр; Center, ставящий каждый элемент на его минимум; Form парами «подпись — поле»; Grid и GridWrap для плиток; Padded и Stack. Отступы берутся из темы: стандартный padding равен 4, внутренний отступ виджета — 8, и это не случайные пиксели, а константы темы, которые можно переопределить. Компоновки вкладываются друг в друга: заголовок в HBox, боковая панель в VBox, содержимое в Grid — и всё это внутри Border. Полный разбор Box-контейнеров и их ловушек — четвёртый урок курса.

Что в Fyne является общим предком и примитивов рисования, и кнопок?

Запуск без цикла событий

Прочитайте код и выберите, что он выведет:

package main

import (
        "fyne.io/fyne/v2/app"
        "fyne.io/fyne/v2/widget"
)

func main() {
        myApp := app.New()
        window := myApp.NewWindow("Мигнёт?")
        window.SetContent(widget.NewLabel("Видите меня?"))
        window.Show()
        // ShowAndRun забыли вызвать
}

Рендеринг: OpenGL, программная растеризация и главный поток#

Кто именно рисует пиксели? На десктопе Fyne открывает окна через GLFW и рисует через OpenGL: в go.mod тулкита прописаны привязки go-gl/gl и go-gl/glfw, а в internal/painter/gl живут шейдеры, которыми прямоугольники, скругления и текст превращаются в графику видеокарты. В сборках под WebAssembly те же вызовы уходят в gl-js — то есть в браузерный WebGL. Второй путь — программная растеризация: software-пейтер из internal/painter/software рисует canvas в обычный image.Image в памяти, без участия видеокарты. Медленнее, но именно на нём построены тесты и headless-среды: пакет test подсовывает приложению SoftwarePainter, а драйвер software умеет рисовать в WindowlessCanvas — рендер без окна вообще. Третье, что полезно знать заранее: GUI живёт в главном потоке операционной системы. Драйвер закрепляет за собой главный поток через runtime.LockOSThread и проводит все операции рисования через очередь; из собственной горутины менять интерфейс напрямую небезопасно — с версии 2.6.0 для этого есть fyne.Do, который ставит вашу функцию в очередь главного потока. Обновление GUI из горутин — тема двадцатого урока.

Платформы: одна кодовая база, пять сред исполнения#

Главный аргумент за Fyne — кроссплатформенность. Десктоп: Windows, macOS, Linux — обычные go run и go build; нужен установленный C-компилятор, а первая сборка на Windows может занять до десяти минут, дальше кеш. Мобильные: Android и iOS собираются командой fyne package -os android -appID my.domain.app или fyne package -os ios; сборка под iOS ведётся с macOS, а -os iossimulator даёт пакет для эмулятора. Готовый пакет ставится утилитой fyne install -os android или платформенными средствами. Посмотреть, как приложение будет выглядеть на телефоне, можно и без пакования: go run -tags mobile запускает мобильную симуляцию. Пятая среда — браузер: с версии 2.5.0 web-драйвер полностью поддерживается, fyne serve поднимает локальный сервер с WebAssembly-сборкой, fyne package -os web готовит файлы для хостинга; ограничения описаны честно — файловые диалоги и хранение документов пока не работают. Требования к среде разработки скромные: Go 1.22 или новее, C-компилятор, системные инструменты — всё перечислено в README.

Как собирается одна и та же программа#

СредаКомандаПримечание
Windows, macOS, Linuxgo run . или go buildнужен C-компилятор; первая сборка до 10 минут
Androidfyne package -os android -appID …установка на устройство: fyne install -os android
iOSfyne package -os ios -appID …сборка с macOS; iossimulator — для эмулятора
Мобильная симуляцияgo run -tags mobileвид телефона без пакования
Web-браузерfyne serve / fyne package -os webс v2.5.0; без файловых диалогов и хранилища документов

Сколько раз в приложении Fyne можно запускать цикл событий (Run)?

Сравнение с Walk: одноплатформенный ветеран#

Перебирая gui go фреймворки, вы почти наверняка наткнётесь на Walk — «Windows Application Library Kit», один из старожилов Go-ниши. Его характер противоположен Fyne: Walk — обёртка над Win32 API и стандартными элементами управления Windows. Отсюда плюс: интерфейс нативный для этой системы, кнопки и списки — настоящие контролы ОС, а не нарисованные поверх. Отсюда и жёсткий потолок: macOS, Linux, мобильные — никак; приложение, собранное с Walk, навсегда привязано к Windows и её API. Стиль кода другой: в Walk принято декларативное описание окна структурами — MainWindow, VBox, TextEdit с AssignTo — что по духу ближе к описаниям интерфейса в других экосистемах, чем к Go-идиомам. Если утилита точно всегда будет под Windows и нужен нативный вид — Walk до сих пор рабочий выбор. Но как только появляется «а теперь пусть работает на маке», начинается переписывание с нуля: Fyne собирает ту же программу на все три десктопные системы из одного кода, и в этом вся цена вопроса.

Сравнение с Gio: ниже уровень, больше контроля#

Gio — второй серьёзный сосед, и сравнивать его честнее всего по уровню абстракции. Gio — immediate mode GUI: программа на каждом кадре заново описывает интерфейс, как это делают игровые движки; нет дерева объектов, живущего между кадрами, есть операция «нарисуй состояние прямо сейчас». README определяет проект одной строкой: «Immediate mode GUI programs in Go» — для Android, iOS, macOS, Linux, FreeBSD, OpenBSD, Windows и WebAssembly, причём веб помечен как экспериментальный. Последствия: Gio даёт предсказуемость и полный контроль отрисовки — ценой ручной работы. Готовых виджетов мало, тема — ваша забота, путь от идеи до формы с полями заметно длиннее, чем в Fyne. Показательна и версия: Gio до сих пор живёт в нулевой мажорной — API ещё может меняться. Fyne — retained-подход: дерево CanvasObject живёт между кадрами, Refresh перерисовывает изменившееся, виджеты и тема идут в комплекте. Для стандартных форм и панелей управления Fyne быстрее в разработке; Gio выбирают, когда интерфейс нестандартный и нужен контроль каждого пикселя. Никто не «лучше» — они про разную цену контроля.

Fyne, Walk и Gio рядом#

FyneWalkGio
ПлатформыWindows, macOS, Linux, iOS, Android, webтолько Windowsдесктопы, iOS, Android, WASM (экспериментально)
Модель UIretained: дерево CanvasObject и Refreshобёртка над Win32-контроламиimmediate mode: кадр собирается каждый раз
Виджеты и темабольшой набор, единая тема в комплектенативные контролы Windowsминимум готового, тема — ваша забота
Порог входасамый низкий из трёхнизкий, если знаком с Win32высокий: ниже уровень абстракции
Выбор, есликроссплатформенное GUI из одной кодовой базыутилита навсегда под Windowsнужен полный контроль отрисовки

Приложение должно работать на Windows, macOS и Android из одной кодовой базы. Какой тулкит отпадает сразу?

Когда Fyne уместен, а когда нет#

Fyne — правильный выбор для внутренних инструментов, настольных утилит, панелей управления, клиентов к собственному API и учебных проектов: везде, где нужна форма с полями, кнопками и списками на трёх десктопных системах, а язык команды — Go. README подчёркивает переносимость: приложения работают без предустановленных библиотек — пользователю не нужны ни рантайм, ни пакеты зависимостей, только ваш бинарник. Честный список, где Fyne не лучший вариант. Игры: тулкит не для этого, в Go для игр есть отдельные инструменты вроде Ebiten. Тяжёлая 3D-графика и нестандартные медиаплееры — возможны, но вы окажетесь на низком уровне canvas раньше, чем рассчитывали. Пиксель-в-пиксель нативный вид каждой ОС — не про Fyne: тема единая, «кнопка как в Windows 11» из коробки не получится. Кросс-компиляция с машины на машину усложняется cgo: собирать под чужую платформу удобнее утилитой fyne-cross с контейнерами — это тема двадцать третьего урока. И веб: работает, но ограничения web-драйвера заметны — для сайта берите обычный фронтенд.

Соберите каркас формы

Восстановите четыре пропущенных вызова каркаса: приложение, окно, содержимое, запуск.

package main import ( "fyne.io/fyne/v2/app" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/widget" ) func main() { myApp := () // приложение с драйвером платформы window := myApp.("Форма") // окно с заголовком window.(container.NewVBox( // содержимое окна widget.NewLabel("Имя:"), widget.NewEntry(), )) () // показать окно и запустить цикл событий }

Каркас программы по строкам

Соберите минимальную Fyne-программу: от объявления пакета до запуска цикла событий.

Строки

Ваша программа

Нажимайте на строки слева, чтобы собрать программу

Маршрут курса и что дальше#

Дальше по курсу так. Второй урок ставит тулкит и запускает первое окно: app.New, SetContent и run loop под микроскопом (02-pervoe-okno). Третий — базовые виджеты Label, Button, Entry, Check, Select; четвёртый — Box-контейнеры и компоновки, тизер которых был выше. Седьмой урок уходит в canvas и примитивы рисования, восьмой собирает собственный виджет на WidgetRenderer — интерфейсная модель из этого урока там окупится полностью. Дальше списки и коллекции, таблицы, вкладки, диалоги, темы, привязка данных, многопоточность и сборка под мобильные и десктоп; полная программа из 25 уроков — на странице курса Fyne. Финальный проект — менеджер задач: списки, темы, сохранение состояния. Если вы прошли базовый курс этого самоучителя, опыт цельного приложения у вас уже есть: 25-pervoe-prilozhenie собирал консольный менеджер заметок. Здесь вы соберёте такой же по смыслу, но с окном, кнопками и мышью — и он будет работать там же, где вы: на вашей системе.

Термины урока

Термин

Fyne

нажмите, чтобы перевернуть
Определение

GUI-тулкит и app-API на Go: виджеты, компоновка и тема написаны на Go, рендер через OpenGL; одна кодовая база для Windows, macOS, Linux, iOS, Android и web.

1 / 6

Песочница урока

Редактируйте код и запускайте его прямо здесь — интерпретатор работает в браузере, ничего устанавливать не нужно. За каждый запуск — +2 XP.

Виртуальный экран

HTML-модель виджет-дерева fyne
Знакомство с fynefyne · мок

GUI на Go — это fyne

Виджет-дерево рисуется в виртуальном экране.

Журнал событий

Экран собран: «Знакомство с fyne»

Коротко: что запомнить

  • Fyne — GUI-тулкит на Go: виджеты, layout и тема — Go-код; для сборки нужен C-компилятор из-за cgo-привязок к OpenGL и GLFW.
  • Всё нарисованное — fyne.CanvasObject; виджет добавляет поведение, внешний вид живёт в WidgetRenderer, обновление — через Refresh().
  • Цикл событий один: ShowAndRun в конце main, повторный Run приводит к ошибкам, код после Run выполняется при выходе.
  • Одна кодовая база — Windows, macOS, Linux, Android, iOS и web (fyne package -os …); web-драйвер полностью поддерживается с v2.5.0.
  • Рендер двойной: OpenGL на десктопе и мобильных, программная растеризация в память — для тестов и headless-сред.
  • Walk — только Windows и Win32-контролы; Gio — immediate mode ниже уровнем; Fyne — самый короткий путь к кроссплатформенной форме.

Домашнее задание

Поставьте тулкит локально: go get fyne.io/fyne/v2@latest, затем go mod tidy после первого импорта. Запустите hello world из урока, поменяйте заголовок окна и текст кнопки, затем выполните go run -tags mobile и сравните вид с десктопным. Прочитайте раздел Architecture в docs.fyne.io про организацию пакетов и выпишите, какие пакеты вам уже знакомы из этого урока, а какие встретятся позже.

Личные заметкиПусто
Хранятся только в вашем браузере (Fyne · Знакомство с Fyne: GUI на Go)

Вопросы и ответы по уроку

Нужны ли Android SDK и Xcode для разработки под мобильные?

Писать и отлаживать логику можно на десктопе и в мобильной симуляции (go run -tags mobile). Для сборки пакета под Android нужен Android SDK, под iOS — Xcode на macOS: fyne package сам вызывает платформенные инструменты.

Fyne выглядит нативно на каждой системе?

Нет, и это честная особенность: тема одна, вдохновлена Material Design, поэтому на Windows, macOS и Linux приложение выглядит одинаково. Нативные контролы из коробки даёт обёртка Walk — но только под Windows.

Можно ли собрать Fyne-приложение для браузера?

Да: fyne serve для локальной проверки и fyne package -os web для хостинга. С версии 2.5.0 web-драйвер полностью поддерживается, но не завершён на сто процентов: файловые диалоги и хранение документов пока недоступны.

Термины урока

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

Сравните с альтернативами

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

Следующая ступень учебного пути

Cobra25 уроков~10 чпрактика25 уроков уже доступны

Cobra: CLI-приложения на Go

Интерактивный курс Cobra — фреймворка для CLI на Go: команды, флаги, конфиги Viper, автодополнение. 25 уроков с примерами кода, тестами и итоговым приложением.

  • Создавать CLI-приложения с деревом команд на Cobra
  • Работать с аргументами, флагами и их привязкой к конфигу
  • Управлять конфигурацией через Viper: файлы, env, приоритеты
  • Писать хуки PreRun/PostRun и корректно обрабатывать ошибки