Другое

Какой макет выбрать для десктопного приложения на Go с Fyne

Руководство по выбору оптимального макета для создания десктопного приложения на Go с использованием библиотеки Fyne. Реализация сайдбара и многострочного поля ввода.

Какой макет (Layout) выбрать для создания desktop приложения на Go с использованием библиотеки Fyne?
Как реализовать сайдбар с кнопками и контентную область с многострочным полем ввода?

Я начинающий разработчик на Go, который создал парсер контента для консольного приложения. Теперь пытаюсь создать десктопное приложение с использованием GUI библиотеки Fyne, но запутался в документации и не могу подобрать оптимальный вариант макета.

Требуется создать окно размером примерно 600x800 пикселей с:

  • Правым сайдбаром с кнопками фиксированной ширины около 150 px
  • Контентной областью с виджетом для ввода многострочного текста, который занимает всё оставшееся пространство

Подскажите, какой макет лучше всего подходит для такой компоновки и как оптимально расположить виджеты в окне?

Для создания десктопного приложения на Go с библиотекой Fyne с правым сайдбаром и контентной областью лучше всего подходят Border контейнер или Split контейнер. Оптимальным решением будет комбинация этих контейнеров для достижения желаемой компоновки.


Содержание


Основные типы макетов в Fyne

Fyne предоставляет несколько типов контейнеров для организации интерфейса:

  1. container.NewBorder – создает контейнер с боковыми панелями, верхним и нижним колонтитулами
  2. container.NewSplit – делит область на две части вертикально (VSplit) или горизонтально (HSplit)
  3. container.NewVBox – вертикальный контейнер для размещения виджетов друг под другом
  4. container.NewHBox – горизонтальный контейнер для размещения виджетов рядом

Для вашей задачи с правым сайдбаром идеальным выбором будет container.NewBorder или container.NewSplit.

Рекомендуемый подход для вашей задачи

Для создания окна 600x800 px с правым сайдбаром шириной 150 px и контентной областью многострочного ввода:

go
// Основной контейнер с правой боковой панелью
sidebar := container.NewBorder(
    nil, // верхний колонтитул (nil = пусто)
    nil, // нижний колонтитул (nil = пусто)
    nil, // левая панель (nil = пусто)
    container.NewVBox( // правая боковая панель с кнопками
        widget.NewButton("Кнопка 1", func() { /* действие */ }),
        widget.NewButton("Кнопка 2", func() { /* действие */ }),
    ),
)

// Основной контейнер
content := container.NewBorder(
    nil,
    nil,
    nil,
    sidebar,
)

// Многострочное поле ввода
textArea := widget.NewMultiLineEntry()
textArea.SetPlaceHolder("Введите текст здесь…")

// Добавляем поле ввода в основную область
mainContent := container.NewScroll(textArea)
content.Objects()[1].(*widget.Container).Add(mainContent)

Пример реализации с Border контейнером

go
package main

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

func main() {
	myApp := app.New()
	window := myApp.NewWindow("Мое приложение")
	window.Resize(fyne.NewSize(600, 800))

	// Создаем кнопки для сайдбара
	button1 := widget.NewButton("Обновить", func() {
		println("Обновление контента")
	})
	button2 := widget.NewButton("Сохранить", func() {
		println("Сохранение контента")
	})
	button3 := widget.NewButton("Выход", func() {
		window.Close()
	})

	// Правый сайдбар с фиксированной шириной
	sidebar := container.NewBorder(
		nil, // верхний колонтитул
		nil, // нижний колонтитул
		nil, // левая панель
		container.NewVBox( // правая боковая панель
			button1,
			button2,
			button3,
		),
	)

	// Многострочное поле ввода
	textArea := widget.NewMultiLineEntry()
	textArea.SetPlaceHolder("Введите или вставьте ваш текст здесь…")

	// Основная контентная область
	contentContainer := container.NewScroll(textArea)

	// Собираем все вместе
	finalLayout := container.NewBorder(
		nil, // верхний колонтитул
		nil, // нижний колонтитул
		nil, // левая панель
		sidebar,
	)

	// Добавляем контентную область в основную часть
	if len(finalLayout.Objects()) > 1 {
		finalLayout.Objects()[1].(*widget.Container).Add(contentContainer)
	}

	window.SetContent(finalLayout)
	window.ShowAndRun()
}

Пример реализации с Split контейнером

go
package main

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

func main() {
	myApp := app.New()
	window := myApp.NewWindow("Мое приложение")
	window.Resize(fyne.NewSize(600, 800))

	// Создаем кнопки для сайдбара
	buttons := []*widget.Button{
		widget.NewButton("Файл", func() { println("Действие файла") }),
		widget.NewButton("Редактировать", func() { println("Действие редактирования") }),
		widget.NewButton("Вид", func() { println("Действие вида") }),
		widget.NewButton("Справка", func() { println("Действие справки") }),
	}

	// Контейнер для кнопок
	sidebarContainer := container.NewVBox()
	for _, btn := range buttons {
		sidebarContainer.Add(btn)
	}

	// Многострочное поле ввода
	textArea := widget.NewMultiLineEntry()
	textArea.SetPlaceHolder("Введите текст…")

	// Основная контентная область с прокруткой
	contentContainer := container.NewScroll(textArea)

	// Создаем разделитель между сайдбаром и контентом
	split := container.NewHSplit(
		contentContainer,
		sidebarContainer,
	)

	// Устанавливаем начальное положение разделителя (около 450 px для контента)
	split.SetOffset(0.75) // 75 % ширины для контента, 25 % для сайдбара

	window.SetContent(split)
	window.ShowAndRun()
}

Оптимизация многострочного поля ввода

Для многострочного поля ввода (widget.NewMultiLineEntry) полезные методы:

go
textArea := widget.NewMultiLineEntry()

// Настройка плейсхолдера
textArea.SetPlaceHolder("Введите текст здесь…")

// Установка текста
textArea.SetText("Пример текста\nс переносом строк")

// Получение текста
text := textArea.Text

// Включение/выключение редактирования
textArea.Disable() // или textArea.Enable()

// Настройка размера шрифта
textArea.TextStyle = fyne.TextStyle{Bold: true}

Полный пример приложения

Вот полный пример, объединяющий все элементы:

go
package main

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

func main() {
	// Создание приложения и окна
	a := app.New()
	w := a.NewWindow("Контент‑парсер")
	w.Resize(fyne.NewSize(600, 800))
	w.SetCloseIntercept(func() {
		println("Приложение закрыто")
	})

	// Создание кнопок для сайдбара
	buttons := []*widget.Button{
		widget.NewButton("Парсить", func() {
			println("Начало парсинга…")
		}),
		widget.NewButton("Очистить", func() {
			textArea.SetText("")
		}),
		widget.NewButton("Сохранить", func() {
			println("Сохранение: " + textArea.Text)
		}),
		widget.NewButton("Загрузить", func() {
			println("Загрузка файла…")
		}),
		widget.NewButton("Настройки", func() {
			println("Открытие настроек…")
		}),
	}

	// Контейнер для кнопок с отступами
	sidebar := container.NewVBox(
		widget.NewLabel("Панель управления"),
		widget.NewSeparator(),
	)
	for _, btn := range buttons {
		sidebar.Add(btn)
		sidebar.Add(widget.NewSeparator())
	}

	// Многострочное поле ввода
	textArea := widget.NewMultiLineEntry()
	textArea.SetPlaceHolder("Введите URL или текст для парсинга…\nПоддерживается несколько строк")
	textArea.SetText("https://example.com\nhttps://test.com")

	// Область контента с прокруткой
	content := container.NewScroll(textArea)

	// Создание главного контейнера с разделением
	mainLayout := container.NewHSplit(content, sidebar)
	mainLayout.SetOffset(0.75) // 75 % для контента, 25 % для сайдбара

	// Добавляем заголовок
	header := container.NewHBox(
		widget.NewLabel("Контент‑парсер"),
		widget.NewLabel("v1.0"),
	)

	// Финальная компоновка
	finalLayout := container.NewBorder(
		header, // верхний колонтитул
		nil,    // нижний колонтитул
		nil,    // левая панель
		nil,    // правая панель
		mainLayout,
	)

	w.SetContent(finalLayout)
	w.ShowAndRun()
}

Советы по адаптации под разные экраны

  1. Адаптивный размер сайдбара:

    go
    // Для автоматической адаптации ширины сайдбара
    sidebar := container.NewVBox(buttons...)
    sidebar.Resize(fyne.NewSize(150, sidebar.MinSize().Height))
    
  2. Минимальные и максимальные размеры:

    go
    textArea.Resize(fyne.NewSize(400, 600))
    textArea.SetMinSize(fyne.NewSize(300, 400))
    
  3. Обработка изменения размера окна:

    go
    w.ResizeCallback = func(size fyne.Size) {
        // Логика адаптации интерфейса
    }
    
  4. Использование Grid контейнера для сложных компоновок:

    go
    grid := container.NewGridWithRows(2,
        header,
        container.NewHSplit(content, sidebar),
    )
    

С Border контейнером вы получаете более строгий контроль над компоновкой, а Split контейнер обеспечивает гибкость и возможность изменения размера пользователем. Для начинающего разработчика Border контейнер будет проще в понимании и использовании.

Авторы
Проверено модерацией
Модерация