Введение
В языковой экосистеме Go графический интерфейс всегда был недостатком, не говоря уже о кроссплатформенном графическом интерфейсе.fyneБольшой шаг вперед.fyneнаписан на языке Goкроссплатформенныйбиблиотека пользовательского интерфейса, ее можно легко портировать на мобильные устройства.fyneОн очень прост в использовании, а также обеспечиваетfyneКоманда для упаковки статических ресурсов и приложений. Мы начнем с краткого введения в основные элементы управления и макеты, а затем опишем, как опубликоватьfyneзаявление.
быстрый в использовании
Код в этой статье использует модули Go.
Сначала инициализируйте:
$ mkdir fyne && cd fyne
$ go mod init github.com/darjun/go-daily-lib/fyne
из-заfyneСодержит некоторый код C/C++, поэтому необходимоgccинструмент сборки. В Linux/Mac OSX,gccВ основном он стандартный, у нас есть 3 способа его установки на windowsgccЦепочка инструментов:
- MSYS2 + MingW-w64:www.msys2.org/;
- TDM-GCC:Банк JM EU.GitHub.IO/heard-GCC/Dow…;
- Cygwin:www.cygwin.com/.
Эта статья выбираетTDM-GCCспособ установки. прибытьБанк JM EU.GitHub.IO/heard-GCC/Dow…Загрузите установщик и установите его. При нормальных обстоятельствах программа установки автоматически установитPATHдорожка. Откройте командную строку, введитеgcc -v. Если информация о версии выводится нормально, установка прошла успешно и переменные среды заданы правильно.
Установитьfyne:
$ go get -u fyne.io/fyne
На этом подготовительная работа завершена, и мы приступаем к кодированию. По соглашению сначалаHello, WorldПрограмма запускается:
package main
import (
"fyne.io/fyne"
"fyne.io/fyne/app"
"fyne.io/fyne/widget"
)
func main() {
myApp := app.New()
myWin := myApp.NewWindow("Hello")
myWin.SetContent(widget.NewLabel("Hello Fyne!"))
myWin.Resize(fyne.NewSize(200, 200))
myWin.ShowAndRun()
}
Результаты приведены ниже:
fyneиспользование простое. каждыйfyneПрограмма состоит из двух частей, одна из которых является прикладным объектомmyApp,пройти черезapp.New()Создайте. Другой - объект окна через объект приложения.myAppсоздаватьmyApp.NewWindow("Hello").myApp.NewWindow()Строка, передаваемая в метод, является заголовком окна.
fyneПредоставляет множество часто используемых компонентов черезwidget.NewXXX()Создайте(XXXимя компонента). В приведенном выше примере мы создалиLabelуправления, а затем установить в окно. Наконец, позвонитеmyWin.ShowAndRun()Запустите программу. ФактическиmyWin.ShowAndRun()Эквивалентно
myWin.Show()
myApp.Run()
myWin.Show()окно дисплея,myApp.Run()Запустите цикл событий.
Будь осторожен,fyneРазмер окна по умолчанию устанавливается в соответствии с шириной и высотой содержимого. выше мы называемmyWin.Resize()Размер устанавливается вручную. В противном случае окно может только удалить строкуHello Fyne!.
fyneРазделение структуры пакета
fyneРазделите функциональность на несколько подпакетов:
-
fyne.io/fyne: предоставить всеfyneОсновные определения, общие для кода приложения, включая типы данных и интерфейсы; -
fyne.io/fyne/app: Предоставляет API для создания приложений; -
fyne.io/fyne/canvas:поставкаFyneиспользуемый API рисования; -
fyne.io/fyne/dialog: Предоставляет диалоговые компоненты; -
fyne.io/fyne/layout: Предоставляет различные макеты интерфейса; -
fyne.io/fyne/widget: содержит множество компонентов,fyneВсе элементы управления формой и интерактивные элементы находятся в этом подпакете.
Canvas
существуетfyneВ приложении все элементы отображения отрисовываются на холсте (Canvas)Вверх. Эти элементы являются объектами холста (CanvasObject). передачаCanvas.SetContent()метод для установки содержимого холста.Canvasобщий вид и компоновка(Layout)контейнер(Container) использовать вместе.canvasНекоторые основные объекты холста предоставляются в подпакете:
package main
import (
"image/color"
"math/rand"
"fyne.io/fyne"
"fyne.io/fyne/app"
"fyne.io/fyne/canvas"
"fyne.io/fyne/layout"
"fyne.io/fyne/theme"
)
func main() {
a := app.New()
w := a.NewWindow("Canvas")
rect := canvas.NewRectangle(color.White)
text := canvas.NewText("Hello Text", color.White)
text.Alignment = fyne.TextAlignTrailing
text.TextStyle = fyne.TextStyle{Italic: true}
line := canvas.NewLine(color.White)
line.StrokeWidth = 5
circle := canvas.NewCircle(color.White)
circle.StrokeColor = color.Gray{0x99}
circle.StrokeWidth = 5
image := canvas.NewImageFromResource(theme.FyneLogo())
image.FillMode = canvas.ImageFillOriginal
raster := canvas.NewRasterWithPixels(
func(_, _, w, h int) color.Color {
return color.RGBA{uint8(rand.Intn(255)),
uint8(rand.Intn(255)),
uint8(rand.Intn(255)), 0xff}
},
)
gradient := canvas.NewHorizontalGradient(color.White, color.Transparent)
container := fyne.NewContainerWithLayout(
layout.NewGridWrapLayout(fyne.NewSize(150, 150)),
rect, text, line, circle, image, raster, gradient))
w.SetContent(container)
w.ShowAndRun()
}
Результат работы программы следующий:
canvas.Rectangleэто простейший объект холста, черезcanvas.NewRectangle()Создайте, передайте цвет заливки.
canvas.Textэто объект холста, который отображает текст черезcanvas.NewText()Создать, передав текстовую строку и цвет. Этот объект устанавливает выравнивание и стиль шрифта. Выравнивание по настройкеTextобъектAlignmentЗначение поля, значения:
-
TextAlignLeading: выравнивание по левому краю; -
TextAlignCenter: выравнивание по центру; -
TextAlignTrailing: Выровнено по правому краю.
стиль шрифта, установивTextобъектTextStyleзначение поля,TextStyleявляется структурой:
type TextStyle struct {
Bold bool
Italic bool
Monospace bool
}
В соответствующем поле установлено значениеtrueБудут отображены соответствующие стили:
-
Bold: жирный; -
Italic: курсив; -
Monospace: Системный моноширинный шрифт.
Мы также можем установить переменную окружения с помощьюFYNE_FONTдля одного.ttfфайл для использования внешних шрифтов.
canvas.Lineпредставляет собой отрезок, проходящий черезcanvas.NewLine()Создать, передать в цвете. в состоянии пройтиline.StrokeWidthУстановите ширину сегмента. По умолчанию сегменты линий рисуются из родительского элемента управления или холста.В левом верхнем углуприбытьНижний правыйиз. доступныйline.Move()а такжеline.Resize()Изменить местоположение.
canvas.Circleкруглая, черезcanvas.NewCircle()Создать, передать в цвете. Кроме того черезStrokeColorа такжеStrokeWidthУстановите цвет и ширину круглой границы.
canvas.Imageобраз, который можно создать из загруженного программного ресурса (canvas.NewImageFromResource()), передайте объект ресурса. или создать по пути к файлу (canvas.NewImageFromFile()), укажите путь к файлу. или через построенныйimage.Imageсоздание объекта (canvas.NewImageFromImage()). в состоянии пройтиFillModeУстановите режим заливки изображения:
-
ImageFillStretch: растянуть, заполнить пространство; -
ImageFillContain: сохранять пропорции; -
ImageFillOriginal: сохранить исходный размер без масштабирования.
Следующая программа демонстрирует эти 3 способа создания изображения:
package main
import (
"image"
"image/color"
"fyne.io/fyne"
"fyne.io/fyne/app"
"fyne.io/fyne/canvas"
"fyne.io/fyne/layout"
"fyne.io/fyne/theme"
)
func main() {
a := app.New()
w := a.NewWindow("Hello")
img1 := canvas.NewImageFromResource(theme.FyneLogo())
img1.FillMode = canvas.ImageFillOriginal
img2 := canvas.NewImageFromFile("./luffy.jpg")
img2.FillMode = canvas.ImageFillOriginal
image := image.NewAlpha(image.Rectangle{image.Point{0, 0}, image.Point{100, 100}})
for i := 0; i < 100; i++ {
for j := 0; j < 100; j++ {
image.Set(i, j, color.Alpha{uint8(i % 256)})
}
}
img3 := canvas.NewImageFromImage(image)
img3.FillMode = canvas.ImageFillOriginal
container := fyne.NewContainerWithLayout(
layout.NewGridWrapLayout(fyne.NewSize(150, 150)),
img1, img2, img3)
w.SetContent(container)
w.ShowAndRun()
}
theme.FyneLogo()ресурс значка Fyne,luffy.jpgпредставляет собой файл на диске и, наконец, создаетimage.Image, который генерируется изcanvas.Image.
Последний эффект градиента градиента, есть два типаcanvas.LinearGradient(линейный градиент) иcanvas.RadialGradient(радиальный градиент), который относится к градиенту от одного цвета к другому. Существует два типа линейных градиентовГоризонтальный линейный градиента такжеВертикальный линейный градиентсоответственно черезcanvas.NewHorizontalGradient()а такжеcanvas.NewVerticalGradient()Создайте. проход радиального градиентаcanvas.NewRadialGradient()Создайте. Мы видели эффект горизонтального линейного градиента в приведенном выше примере, давайте посмотрим на эффект радиального градиента:
func main() {
a := app.New()
w := a.NewWindow("Canvas")
gradient := canvas.NewRadialGradient(color.White, color.Transparent)
w.SetContent(gradient)
w.Resize(fyne.NewSize(200, 200))
w.ShowAndRun()
}
Эффект операции следующий:
Радиационный эффект представляет собой градиент от центра к периферии.
Widget
Контроль формы – этоFyneОсновные компоненты приложения. Они адаптируются к текущей теме и обрабатывают взаимодействие с пользователем.
Label
Этикетка(Label) — простейший элемент управления, используемый для отображения строк. это чем-то похоже наcanvas.Text, разница заключается вLabelМожет обрабатывать простое форматирование, например\n:
func main() {
myApp := app.New()
myWin := myApp.NewWindow("Label")
l1 := widget.NewLabel("Name")
l2 := widget.NewLabel("da\njun")
container := fyne.NewContainerWithLayout(layout.NewVBoxLayout(), l1, l2)
myWin.SetContent(container)
myWin.Resize(fyne.NewSize(150, 150))
myWin.ShowAndRun()
}
второйwidget.Labelсередина\nСледующее содержимое будет отображаться на следующей строке:
Button
кнопка (Button) элементы управления позволяют пользователю нажимать, предоставляя пользователю обратную связь.ButtonМожет содержать текст, значки или и то, и другое. передачаwidget.NewButton()Создает текстовую кнопку по умолчанию, передавая текст и функцию обратного вызова без аргументов. Кнопки с иконками нужно называтьwidget.NewButtonWithIcon(), передать текст и параметры обратного вызова, а такжеfyne.ResourceТипы ресурсов значков:
func main() {
myApp := app.New()
myWin := myApp.NewWindow("Button")
btn1 := widget.NewButton("text button", func() {
fmt.Println("text button clicked")
})
btn2 := widget.NewButtonWithIcon("icon", theme.HomeIcon(), func() {
fmt.Println("icon button clicked")
})
container := fyne.NewContainerWithLayout(layout.NewVBoxLayout(), btn1, btn2)
myWin.SetContent(container)
myWin.Resize(fyne.NewSize(150, 50))
myWin.ShowAndRun()
}
Вышеприведенное создает текстовую кнопку и кнопку со значком,themeПодпакет содержит некоторые ресурсы значков по умолчанию, а также могут быть загружены внешние значки. бегать:
Нажмите кнопку, будет вызван соответствующий обратный вызов, попробуйте!
Box
блок управления (Box) — это простой горизонтальный или вертикальный контейнер. Внутренний,BoxИспользуйте макет блока для дочерних элементов управления (Box LayoutПожалуйста, обратитесь к макету текста. Мы можем дать его объекту контроляwidget.NewHBox()илиwidget.NewVBox()Создавайте ящики. или позвоните в уже созданныйwidget.BoxобъектAppend()илиPrepend()Добавьте элементы управления в поле. Первый добавляется в конце, а второй в начале.
func main() {
myApp := app.New()
myWin := myApp.NewWindow("Box")
content := widget.NewVBox(
widget.NewLabel("The top row of VBox"),
widget.NewHBox(
widget.NewLabel("Label 1"),
widget.NewLabel("Label 2"),
),
)
content.Append(widget.NewButton("Append", func() {
content.Append(widget.NewLabel("Appended"))
}))
content.Append(widget.NewButton("Prepend", func() {
content.Prepend(widget.NewLabel("Prepended"))
}))
myWin.SetContent(content)
myWin.Resize(fyne.NewSize(150, 150))
myWin.ShowAndRun()
}
мы можем даже гнездитьсяwidget.BoxЭлементы управления, чтобы вы могли добиться более гибкого макета. Вышеприведенный код добавляет две кнопки, которые были добавлены в головную часть, а хвостовая часть нажата.Label:
Entry
Поле ввода(Entry) элементы управления используются для ввода пользователю простого текстового содержимого. передачаwidget.NewEntry()Вы можете создать элемент управления полем ввода. Обычно мы сохраняем ссылку на элемент управления полем ввода, чтобы получить доступ к егоTextполе для получения содержимого. регистрOnChangedПерезвоните. Всякий раз, когда содержимое изменяется,OnChangedбудет называться. мы можем позвонитьSetReadOnly(true)Устанавливает доступное только для чтения свойство поля ввода. методSetPlaceHolder()Используется для установки строк-заполнителей, установки полейMultilineСделайте так, чтобы поле ввода принимало несколько строк текста. В качестве альтернативы мы можем использоватьNewPasswordEntry()Создайте поле ввода пароля, введенный текст не будет отображаться открытым текстом.
func main() {
myApp := app.New()
myWin := myApp.NewWindow("Entry")
nameEntry := widget.NewEntry()
nameEntry.SetPlaceHolder("input name")
nameEntry.OnChanged = func(content string) {
fmt.Println("name:", nameEntry.Text, "entered")
}
passEntry := widget.NewPasswordEntry()
passEntry.SetPlaceHolder("input password")
nameBox := widget.NewHBox(widget.NewLabel("Name"), layout.NewSpacer(), nameEntry)
passwordBox := widget.NewHBox(widget.NewLabel("Password"), layout.NewSpacer(), passEntry)
loginBtn := widget.NewButton("Login", func() {
fmt.Println("name:", nameEntry.Text, "password:", passEntry.Text, "login in")
})
multiEntry := widget.NewEntry()
multiEntry.SetPlaceHolder("please enter\nyour description")
multiEntry.MultiLine = true
content := widget.NewVBox(nameBox, passwordBox, loginBtn, multiEntry)
myWin.SetContent(content)
myWin.ShowAndRun()
}
Здесь мы реализуем простой интерфейс входа:
Checkbox/Radio/Select
CheckBoxЭто простое поле выбора, каждый выбор независим, например, хобби может быть футбол, баскетбол или и то, и другое. Создать методwidget.NewCheck(), передавая строку параметров (футбол, баскетбол) и функцию обратного вызова. Функция обратного вызова принимаетboolПараметр типа, указывающий, выбрана ли опция.
RadioЭто радиобокс, в каждой группе можно выбрать только один, например пол, это может быть только мужчина или женщина (?). Создать методwidget.NewRadio(), передавая фрагмент строки и функцию обратного вызова в качестве аргументов. Функция обратного вызова принимает строковый параметр, представляющий выбранную опцию. также можно использоватьSelectedПоле считывает выбранный вариант.
SelectЭто раскрывающееся окно выбора.При нажатии отображается раскрывающееся меню.Щелкните, чтобы выбрать. Когда есть много вариантов, лучше использоватьSelect. Создать методwidget.NewSelect(), параметры сNewRadio()Точно так же.
func main() {
myApp := app.New()
myWin := myApp.NewWindow("Choices")
nameEntry := widget.NewEntry()
nameEntry.SetPlaceHolder("input name")
passEntry := widget.NewPasswordEntry()
passEntry.SetPlaceHolder("input password")
repeatPassEntry := widget.NewPasswordEntry()
repeatPassEntry.SetPlaceHolder("repeat password")
nameBox := widget.NewHBox(widget.NewLabel("Name"), layout.NewSpacer(), nameEntry)
passwordBox := widget.NewHBox(widget.NewLabel("Password"), layout.NewSpacer(), passEntry)
repeatPasswordBox := widget.NewHBox(widget.NewLabel("Repeat Password"), layout.NewSpacer(), repeatPassEntry)
sexRadio := widget.NewRadio([]string{"male", "female", "unknown"}, func(value string) {
fmt.Println("sex:", value)
})
sexBox := widget.NewHBox(widget.NewLabel("Sex"), sexRadio)
football := widget.NewCheck("football", func(value bool) {
fmt.Println("football:", value)
})
basketball := widget.NewCheck("basketball", func(value bool) {
fmt.Println("basketball:", value)
})
pingpong := widget.NewCheck("pingpong", func(value bool) {
fmt.Println("pingpong:", value)
})
hobbyBox := widget.NewHBox(widget.NewLabel("Hobby"), football, basketball, pingpong)
provinceSelect := widget.NewSelect([]string{"anhui", "zhejiang", "shanghai"}, func(value string) {
fmt.Println("province:", value)
})
provinceBox := widget.NewHBox(widget.NewLabel("Province"), layout.NewSpacer(), provinceSelect)
registerBtn := widget.NewButton("Register", func() {
fmt.Println("name:", nameEntry.Text, "password:", passEntry.Text, "register")
})
content := widget.NewVBox(nameBox, passwordBox, repeatPasswordBox,
sexBox, hobbyBox, provinceBox, registerBtn)
myWin.SetContent(content)
myWin.ShowAndRun()
}
Здесь мы реализуем простой интерфейс регистрации:
Form
Контроль формы (Form) для многихLabelи элементы управления вводом для макета. если указаноOnSubmitилиOnCancelфункция, элемент управления формы автоматически добавит соответствующийButtonкнопка. мы называемwidget.NewForm()проходить вwidget.FormItemСоздание срезаFormконтролирует. Строка в каждом элементе какLabelтекст, объект управления. созданныйFormобъект может затем вызвать егоAppend(label, widget)метод добавления элементов управления.
func main() {
myApp := app.New()
myWindow := myApp.NewWindow("Form")
nameEntry := widget.NewEntry()
passEntry := widget.NewPasswordEntry()
form := widget.NewForm(
&widget.FormItem{"Name", nameEntry},
&widget.FormItem{"Pass", passEntry},
)
form.OnSubmit = func() {
fmt.Println("name:", nameEntry.Text, "pass:", passEntry.Text, "login in")
}
form.OnCancel = func() {
fmt.Println("login canceled")
}
myWindow.SetContent(form)
myWindow.Resize(fyne.NewSize(150, 150))
myWindow.ShowAndRun()
}
использоватьFormМожно значительно упростить конструкцию формы, используемFormПереработан интерфейс входа выше:
УведомлениеSubmitа такжеCancelКнопки генерируются автоматически!
ProgressBar
индикатор выполнения (ProgressBar) используется для обозначения хода выполнения задачи, например хода загрузки файла. Создать методwidget.NewProgressBar(), минимальное значение по умолчанию равно0.0, максимальное значение1.1,доступныйMin/MaxПолевые настройки. передачаSetValue()способ контролировать прогресс. Другой тип индикатора выполнения — это круговая анимация, которая указывает на выполнение задачи и не может указывать на конкретный статус завершения.
func main() {
myApp := app.New()
myWindow := myApp.NewWindow("ProgressBar")
bar1 := widget.NewProgressBar()
bar1.Min = 0
bar1.Max = 100
bar2 := widget.NewProgressBarInfinite()
go func() {
for i := 0; i <= 100; i ++ {
time.Sleep(time.Millisecond * 500)
bar1.SetValue(float64(i))
}
}()
content := widget.NewVBox(bar1, bar2)
myWindow.SetContent(content)
myWindow.Resize(fyne.NewSize(150, 150))
myWindow.ShowAndRun()
}
Обновление прогресса в другой горутине. Эффект следующий:
TabContainer
Контейнер с этикеткой (TabContainer) позволяет пользователю переключаться между различными контентными панелями. Этикетки могут быть текстовыми или значками. Создать методwidget.NewTabContainer(), входящийwidget.TabItemкак параметр.widget.TabItemдоступныйwidget.NewTabItem(label, widget)Создайте. Метка также может задавать положение:
-
TabLocationBottom: отображается внизу; -
TabLocationLeading: отображается в левом верхнем углу; -
TabLocationTrailing: отображается в правом верхнем углу.
См. пример:
func main() {
myApp := app.New()
myWindow := myApp.NewWindow("TabContainer")
nameLabel := widget.NewLabel("Name: dajun")
sexLabel := widget.NewLabel("Sex: male")
ageLabel := widget.NewLabel("Age: 18")
addressLabel := widget.NewLabel("Province: shanghai")
addressLabel.Hide()
profile := widget.NewVBox(nameLabel, sexLabel, ageLabel, addressLabel)
musicRadio := widget.NewRadio([]string{"on", "off"}, func(string) {})
showAddressCheck := widget.NewCheck("show address?", func(value bool) {
if !value {
addressLabel.Hide()
} else {
addressLabel.Show()
}
})
memberTypeSelect := widget.NewSelect([]string{"junior", "senior", "admin"}, func(string) {})
setting := widget.NewForm(
&widget.FormItem{"music", musicRadio},
&widget.FormItem{"check", showAddressCheck},
&widget.FormItem{"member type", memberTypeSelect},
)
tabs := widget.NewTabContainer(
widget.NewTabItem("Profile", profile),
widget.NewTabItem("Setting", setting),
)
myWindow.SetContent(tabs)
myWindow.Resize(fyne.NewSize(200, 200))
myWindow.ShowAndRun()
}
Приведенный выше код создает простую панель личной информации и панель настроек, нажмитеshow address?Вы можете изменить отображение информации об адресе:
Toolbar
панель инструментов(Toolbar) является неотъемлемой частью многих приложений с графическим интерфейсом. Панель инструментов отображает часто используемые команды в виде иконок, что удобно в использовании. Создать методwidget.NewToolbar(), передать несколькоwidget.ToolbarItemкак параметр. чаще всего используетсяToolbarItemесть команда(Action), разделитель (Separator) и пустой (Spacer), соответственно черезwidget.NewToolbarItemAction(resource, callback)/widget.NewToolbarSeparator()/widget.NewToolbarSpacer()Создайте. Команде необходимо указать обратный вызов, который срабатывает при нажатии.
func main() {
myApp := app.New()
myWindow := myApp.NewWindow("Toolbar")
toolbar := widget.NewToolbar(
widget.NewToolbarAction(theme.DocumentCreateIcon(), func() {
fmt.Println("New document")
}),
widget.NewToolbarSeparator(),
widget.NewToolbarAction(theme.ContentCutIcon(), func() {
fmt.Println("Cut")
}),
widget.NewToolbarAction(theme.ContentCopyIcon(), func() {
fmt.Println("Copy")
}),
widget.NewToolbarAction(theme.ContentPasteIcon(), func() {
fmt.Println("Paste")
}),
widget.NewToolbarSpacer(),
widget.NewToolbarAction(theme.HelpIcon(), func() {
log.Println("Display help")
}),
)
content := fyne.NewContainerWithLayout(
layout.NewBorderLayout(toolbar, nil, nil, nil),
toolbar, widget.NewLabel(`Lorem ipsum dolor,
sit amet consectetur adipisicing elit.
Quidem consectetur ipsam nesciunt,
quasi sint expedita minus aut,
porro iusto magnam ducimus voluptates cum vitae.
Vero adipisci earum iure consequatur quidem.`),
)
myWindow.SetContent(content)
myWindow.ShowAndRun()
}
Панель инструментов общего пользованияBorderLayout, поместите панель инструментов поверх любых других элементов управления, макет будет подробно описан позже. бегать:
Расширенный контроль
Стандартные элементы управления Fyne предоставляют минимальный набор функций и возможность настройки для большинства сценариев применения. Бывают случаи, когда нам нужна более продвинутая функциональность. Помимо написания собственных элементов управления, мы также можем расширить существующие элементы управления. Например, нам нужен элемент управления значкомwidget.IconРеагирует на левый, правый и двойной щелчок мыши. Сначала напишитеКонструктор,передачаExtendBaseWidget()Метод получает основную функцию управления:
type tappableIcon struct {
widget.Icon
}
func newTappableIcon(res fyne.Resource) *tappableIcon {
icon := &tappableIcon{}
icon.ExtendBaseWidget(icon)
icon.SetResource(res)
return icon
}
Затем реализуйте соответствующий интерфейс:
// src/fyne.io/fyne/canvasobject.go
// 鼠标左键
type Tappable interface {
Tapped(*PointEvent)
}
// 鼠标右键或长按
type SecondaryTappable interface {
TappedSecondary(*PointEvent)
}
// 双击
type DoubleTappable interface {
DoubleTapped(*PointEvent)
}
Реализация интерфейса:
func (t *tappableIcon) Tapped(e *fyne.PointEvent) {
log.Println("I have been left tapped at", e)
}
func (t *tappableIcon) TappedSecondary(e *fyne.PointEvent) {
log.Println("I have been right tapped at", e)
}
func (t *tappableIcon) DoubleTapped(e *fyne.PointEvent) {
log.Println("I have been double tapped at", e)
}
Наконец, используйте:
func main() {
a := app.New()
w := a.NewWindow("Tappable")
w.SetContent(newTappableIcon(theme.FyneLogo()))
w.Resize(fyne.NewSize(200, 200))
w.ShowAndRun()
}
Выполнить, щелкните значок консоли, чтобы получить соответствующий вывод:
2020/06/18 06:44:02 I have been left tapped at &{{110 97} {106 93}}
2020/06/18 06:44:03 I have been left tapped at &{{110 97} {106 93}}
2020/06/18 06:44:05 I have been right tapped at &{{88 102} {84 98}}
2020/06/18 06:44:06 I have been right tapped at &{{88 102} {84 98}}
2020/06/18 06:44:06 I have been left tapped at &{{88 101} {84 97}}
2020/06/18 06:44:07 I have been double tapped at &{{88 101} {84 97}}
выходfyne.PointEventСуществуют абсолютные позиции (для левого верхнего угла окна) и относительные позиции (для левого верхнего угла контейнера).
Layout
макет(Layout) — это то, как элементы управления отображаются в интерфейсе и как они расположены. Чтобы интерфейс выглядел хорошо, макет должен быть освоен. Почти все графические интерфейсы предоставляют макет или аналогичный интерфейс. На самом деле, в предыдущем примере мы имеемfyne.NewContainerWithLayout()В функции используется макет.
BoxLayout
Внешний вид коробки (BoxLayout) является наиболее часто используемым макетом. Он упорядочивает все элементы управления в строке или столбце. существуетfyne, мы можем пройтиlayout.NewHBoxLayout()Создайте горизонтальную коробочную компоновку,layout.NewVBoxLayout()Создайте вертикальную коробочную компоновку. Элементы управления в горизонтальной компоновке располагаются в ряд, и каждый элемент управления имеет ширину, равную минимальной ширине его содержимого (MinSize().Width), все они имеют одинаковую высоту, максимальная высота всех элементов управления (MinSize().Height).
Элементы управления в вертикальной компоновке расположены в столбце, каждый элемент управления имеет высоту, равную минимальной высоте его содержимого, и все они имеют одинаковую ширину, которая является максимальной шириной всех элементов управления.
Как правило, вBoxLayoutиспользуется вlayout.NewSpacer()Вспомогательная раскладка, она займет оставшееся место. Для горизонтального расположения блоков добавьтеlayout.NewSpacer(), все элементы управления выравниваются по правому краю. Добавить один после последнего элемента управленияlayout.NewSpacer(), все элементы управления выравниваются по левому краю. Есть спереди и сзади, тогда органы управления выровнены посередине. Если в середине добавитьlayout.NewSpacer(), то другие элементы управления выравниваются с обеих сторон.
func main() {
myApp := app.New()
myWindow := myApp.NewWindow("Box Layout")
hcontainer1 := fyne.NewContainerWithLayout(layout.NewHBoxLayout(),
canvas.NewText("left", color.White),
canvas.NewText("right", color.White))
// 左对齐
hcontainer2 := fyne.NewContainerWithLayout(layout.NewHBoxLayout(),
layout.NewSpacer(),
canvas.NewText("left", color.White),
canvas.NewText("right", color.White))
// 右对齐
hcontainer3 := fyne.NewContainerWithLayout(layout.NewHBoxLayout(),
canvas.NewText("left", color.White),
canvas.NewText("right", color.White),
layout.NewSpacer())
// 中间对齐
hcontainer4 := fyne.NewContainerWithLayout(layout.NewHBoxLayout(),
layout.NewSpacer(),
canvas.NewText("left", color.White),
canvas.NewText("right", color.White),
layout.NewSpacer())
// 两边对齐
hcontainer5 := fyne.NewContainerWithLayout(layout.NewHBoxLayout(),
canvas.NewText("left", color.White),
layout.NewSpacer(),
canvas.NewText("right", color.White))
myWindow.SetContent(fyne.NewContainerWithLayout(layout.NewVBoxLayout(),
hcontainer1, hcontainer2, hcontainer3, hcontainer4, hcontainer5))
myWindow.Resize(fyne.NewSize(200, 200))
myWindow.ShowAndRun()
}
текущий результат:
GridLayout
Макет сетки (GridLayout) Каждая строка имеет фиксированный столбец.Когда количество добавленных элементов управления превышает это значение, следующие элементы управления будут отображаться в новой строке. Создать методlayout.NewGridLayout(cols), передавая количество столбцов в строке.
func main() {
myApp := app.New()
myWindow := myApp.NewWindow("Grid Layout")
img1 := canvas.NewImageFromResource(theme.FyneLogo())
img2 := canvas.NewImageFromResource(theme.FyneLogo())
img3 := canvas.NewImageFromResource(theme.FyneLogo())
myWindow.SetContent(fyne.NewContainerWithLayout(layout.NewGridLayout(2),
img1, img2, img3))
myWindow.Resize(fyne.NewSize(300, 300))
myWindow.ShowAndRun()
}
текущий результат:
Этот макет имеет то преимущество, что когда мы масштабируем интерфейс, элементы управления автоматически изменяются. попробуй~
GridWrapLayout
GridWrapLayoutдаGridLayoutрасширение.GridWrapLayoutПри создании начальныйsize,этоsizeБудет применяться ко всем дочерним элементам управления, каждый дочерний элемент управления поддерживает этоsize. Изначально по одному элементу управления на строку. Если размер интерфейса изменяется, эти дочерние элементы управления перестраиваются. Например, если ширина удвоена, два элемента управления можно расположить в ряд. Что-то вроде плавного макета:
func main() {
myApp := app.New()
myWindow := myApp.NewWindow("Grid Wrap Layout")
img1 := canvas.NewImageFromResource(theme.FyneLogo())
img2 := canvas.NewImageFromResource(theme.FyneLogo())
img3 := canvas.NewImageFromResource(theme.FyneLogo())
myWindow.SetContent(
fyne.NewContainerWithLayout(
layout.NewGridWrapLayout(fyne.NewSize(150, 150)),
img1, img2, img3))
myWindow.ShowAndRun()
}
исходный:
Увеличить ширину:
Чтобы увеличить ширину:
BorderLayout
оформление границы (BorderLayout) чаще используется для создания пользовательских интерфейсов, в приведенном выше примереToolbarвообще иBorderLayoutДля использования с. Создать методlayout.NewBorderLayout(top, bottom, left, right), передать верхний, нижний, левый и правый объекты управления соответственно. элементы управления добавляются в контейнер, если ониграницаОбъект отображается в соответствующей позиции, а остальные отображаются в центре:
func main() {
myApp := app.New()
myWindow := myApp.NewWindow("Border Layout")
left := canvas.NewText("left", color.White)
right := canvas.NewText("right", color.White)
top := canvas.NewText("top", color.White)
bottom := canvas.NewText("bottom", color.White)
content := widget.NewLabel(`Lorem ipsum dolor,
sit amet consectetur adipisicing elit.
Quidem consectetur ipsam nesciunt,
quasi sint expedita minus aut,
porro iusto magnam ducimus voluptates cum vitae.
Vero adipisci earum iure consequatur quidem.`)
container := fyne.NewContainerWithLayout(
layout.NewBorderLayout(top, bottom, left, right),
top, bottom, left, right, content,
)
myWindow.SetContent(container)
myWindow.ShowAndRun()
}
Эффект:
FormLayout
макет формы (FormLayout) на самом деле 2-столбцовыйGridLayout, но с некоторой доработкой формы.
func main() {
myApp := app.New()
myWindow := myApp.NewWindow("Border Layout")
nameLabel := canvas.NewText("Name", color.Black)
nameValue := canvas.NewText("dajun", color.White)
ageLabel := canvas.NewText("Age", color.Black)
ageValue := canvas.NewText("18", color.White)
container := fyne.NewContainerWithLayout(
layout.NewFormLayout(),
nameLabel, nameValue, ageLabel, ageValue,
)
myWindow.SetContent(container)
myWindow.Resize(fyne.NewSize(150, 150))
myWindow.ShowAndRun()
}
текущий результат:
CenterLayout
CenterLayoutОтображает все элементы управления в контейнере в центре в том порядке, в котором они были переданы. Последний входящий элемент управления отображает верхний слой.CenterLayoutВсе элементы управления сохранят свой минимальный размер (размер для хранения их содержимого).
func main() {
myApp := app.New()
myWindow := myApp.NewWindow("Center Layout")
image := canvas.NewImageFromResource(theme.FyneLogo())
image.FillMode = canvas.ImageFillOriginal
text := canvas.NewText("Fyne Logo", color.Black)
container := fyne.NewContainerWithLayout(
layout.NewCenterLayout(),
image, text,
)
myWindow.SetContent(container)
myWindow.ShowAndRun()
}
результат операции:
нитьFyne Logoотображается поверх изображения. если мы положимtextа такжеimageЕсли порядок обратный, строка будет заблокирована изображением и не будет видна. Попробуйте ~
MaxLayout
MaxLayoutа такжеCenterLayoutаналогично, за исключением того, чтоMaxLayoutЗаставляет элементы внутри контейнера отображаться в максимальном размере (равном размеру контейнера). Внимательные друзья могли обнаружить, что вCenterLayoutв примере. Мы устанавливаем режим заполнения изображения наImageFillOriginal. Если вы не установите режим заливки, изображение по умолчаниюMinSizeдля(1, 1). Могуfmt.Println(image.MinSize())Проверять. Таким образом, картинка не будет отображаться в интерфейсе.
существуетMaxLayout, нам не нужно этого делать:
func main() {
myApp := app.New()
myWindow := myApp.NewWindow("Max Layout")
image := canvas.NewImageFromResource(theme.FyneLogo())
text := canvas.NewText("Fyne Logo", color.Black)
container := fyne.NewContainerWithLayout(
layout.NewMaxLayout(),
image, text,
)
myWindow.SetContent(container)
myWindow.Resize(fyne.Size(200, 200))
myWindow.ShowAndRun()
}
результат операции:
Уведомление,canvas.TextОтображается с выравниванием по левому краю. Чтобы выровнять по центру, установите егоAlignmentсобственностьfyne.TextAlignCenter.
пользовательский макет
Встроенные макеты в подпакетахlayoutсередина. все они сбылисьfyne.Layoutинтерфейс:
// src/fyne.io/fyne/layout.go
type Layout interface {
Layout([]CanvasObject, Size)
MinSize(objects []CanvasObject) Size
}
Чтобы реализовать собственный макет, просто реализуйте этот интерфейс. Ниже мы реализуем ступенчатую (диагональную) компоновку, как диагональ матрицы, сверху слева направо снизу. Сначала определите новый тип. затем реализовать интерфейсfyne.Layoutдва метода:
type diagonal struct {
}
func (d *diagonal) MinSize(objects []fyne.CanvasObject) fyne.Size {
w, h := 0, 0
for _, o := range objects {
childSize := o.MinSize()
w += childSize.Width
h += childSize.Height
}
return fyne.NewSize(w, h)
}
func (d *diagonal) Layout(objects []fyne.CanvasObject, containerSize fyne.Size) {
pos := fyne.NewPos(0, 0)
for _, o := range objects {
size := o.MinSize()
o.Resize(size)
o.Move(pos)
pos = pos.Add(fyne.NewPos(size.Width, size.Height))
}
}
MinSize()Возвращает все дочерние элементы управленияMinSizeСумма.Layout()Располагает элементы управления сверху слева вниз справа. Затем используйте:
func main() {
myApp := app.New()
myWindow := myApp.NewWindow("Diagonal Layout")
img1 := canvas.NewImageFromResource(theme.FyneLogo())
img1.FillMode = canvas.ImageFillOriginal
img2 := canvas.NewImageFromResource(theme.FyneLogo())
img2.FillMode = canvas.ImageFillOriginal
img3 := canvas.NewImageFromResource(theme.FyneLogo())
img3.FillMode = canvas.ImageFillOriginal
container := fyne.NewContainerWithLayout(
&diagonal{},
img1, img2, img3,
)
myWindow.SetContent(container)
myWindow.ShowAndRun()
}
результат операции:
fyne demo
fyneПредоставляется демонстрация, демонстрирующая использование большинства элементов управления и макетов. Вы можете установить его с помощью следующей команды, выполните:
$ go get fyne.io/fyne/cmd/fyne_demo
$ fyne_demo
Изображение эффекта:
fyneЗаказ
fyneБиблиотека предоставлена для удобства разработчиковfyneЗаказ.fyneЕго можно использовать для упаковки статических ресурсов в исполняемые программы, а также для упаковки всего приложения в публикуемую форму.fyneКоманда устанавливается следующей командой:
$ go get fyne.io/fyne/cmd/fyne
После завершения установкиfyneв$GOPATH/binкаталог,$GOPATH/binдобавить в систему$PATHВ можно напрямую бегатьfyneзаказ.
статические ресурсы
Фактически, в предыдущем примере мы использовали его много раз.fyneВстроенные статические ресурсы, наиболее часто используемые из нихfyne.FyneLogo(). Ниже у нас две картинкиimage1.png/image2.jpg. Мы используемfyne bundleКоманда упаковывает эти два изображения в код:
$ fyne bundle image1.png >> bundled.go
$ fyne bundle -append image2.jpg >> bundled.go
Вторая команда указывает-appendОпция означает добавление к существующему файлу, результирующий файл выглядит следующим образом:
// bundled.go
package main
import "fyne.io/fyne"
var resourceImage1Png = &fyne.StaticResource{
StaticName: "image1.png",
StaticContent: []byte{...}}
var resourceImage2Jpg = &fyne.StaticResource{
StaticName: "image2.jpg",
StaticContent: []byte{...}}
На самом деле содержимое изображения хранится в байтовом слайсе, и мы можем вызвать его в кодеcanvas.NewImageFromResource(), входящийresourceImage1PngилиresourceImage2Jpgсоздаватьcanvas.Imageобъект.
func main() {
myApp := app.New()
myWindow := myApp.NewWindow("Bundle Resource")
img1 := canvas.NewImageFromResource(resourceImage1Png)
img1.FillMode = canvas.ImageFillOriginal
img2 := canvas.NewImageFromResource(resourceImage2Jpg)
img2.FillMode = canvas.ImageFillOriginal
img3 := canvas.NewImageFromResource(theme.FyneLogo())
img3.FillMode = canvas.ImageFillOriginal
container := fyne.NewContainerWithLayout(
layout.NewGridLayout(1),
img1, img2, img3,
)
myWindow.SetContent(container)
myWindow.ShowAndRun()
}
результат операции:
Обратите внимание, что, поскольку теперь есть два файла, его нельзя использовать.go run main.go, следует использоватьgo run ..
theme.FyneLogo()На самом деле он тоже заранее запакован в код.bundled-icons.go:
// src/fyne.io/fyne/theme/icons.go
func FyneLogo() fyne.Resource {
return fynelogo
}
// src/fyne.io/fyne/theme/bundled-icons.go
var fynelogo = &fyne.StaticResource{
StaticName: "fyne.png",
StaticContent: []byte{}}
Опубликовать приложение
Публикация приложения изображения для нескольких операционных систем — очень сложная задача. Приложения с графическим интерфейсом обычно имеют значки и некоторые метаданные.fyneКоманды обеспечивают поддержку публикации приложений на нескольких платформах. использоватьfyne packageКоманда создаст приложение, которое можно будет установить/запустить на других компьютерах. В Windows,fyne packageсоздаст.exeдокумент. В macOS.appдокумент. В Linux.tar.xzфайл, который можно установить вручную.
Мы упаковываем вышеупомянутое приложение вexeдокумент:
$ fyne package -os windows -icon icon.jpg
Приведенная выше команда создаст два файла в одном каталоге.bundle.exeа такжеfyne.syso, копирование этих двух файлов в любой каталог или на другой компьютер Windows можно выполнить напрямую, дважды щелкнувbundle.exeбегать. Никаких других зависимостей.
fyneТакже поддерживается кросс-компиляция, и приложения для Mac можно скомпилировать в Windows, но для этого необходимо установить дополнительные инструменты.Если вам интересно, вы можете изучить их самостоятельно.
Суммировать
fyneПредоставляет множество компонентов и функций, мы представляем только самую основную часть, а также буфер обмена, сочетания клавиш, полосы прокрутки, меню и так далее.fyneВ команде реализована упаковка статических ресурсов и приложений, что очень удобно.fyneЕсть и другие расширенные функции, которые вы можете исследовать и копать~
Если вы найдете забавную и простую в использовании языковую библиотеку Go, вы можете отправить сообщение о проблеме в ежедневной библиотеке Go GitHub😄
Ссылаться на
- точно GitHub:GitHub.com/что насчет сборов-IO/fyn…
- официальный сайт Файн:fyne.io/
- официальное вводное руководство fyne:разработчик Что с расходами IO/input/intro...
- Перейти на ежедневный репозиторий GitHub:GitHub.com/Darenjun/go-of…
я
мой блог:darjun.github.io
Добро пожаловать, чтобы обратить внимание на мою общедоступную учетную запись WeChat [GoUpUp], учитесь вместе и добивайтесь прогресса вместе ~