Вопрос к знатокам Go и Fyne по поводу изменения записей таблиц в приложении
Имеется следующий код на Golang с использованием Fyne и Gorm:
package main
import (
"fmt"
"strings"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
// Структура для создания таблицы в базе данных
type Song struct {
Name string
Artist string
Album string
Year string
Country string
Genres string
Tags string
gorm.Model
}
func main() {
// Создаём окно приложения с тёмной темой, задаем его размер и расположение на экране
a := app.New()
w := a.NewWindow("tune")
a.Settings().SetTheme(theme.DarkTheme())
w.Resize(fyne.NewSize(800, 600))
w.CenterOnScreen()
// Подключаемся к базе данных
db, err := gorm.Open(sqlite.Open("tune.db"), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
// Создаем таблицу, если ее еще нет
db.AutoMigrate(&Song{})
// Создаем форму для ввода данных о композиции
form := widget.NewForm(
&widget.FormItem{Text: "Song", Widget: widget.NewEntry()},
&widget.FormItem{Text: "Artist", Widget: widget.NewEntry()},
&widget.FormItem{Text: "Album", Widget: widget.NewEntry()},
&widget.FormItem{Text: "Year", Widget: widget.NewEntry()},
&widget.FormItem{Text: "Country", Widget: widget.NewEntry()},
)
//Совокупность полей для ввода жанров
genresEntry := []*widget.Entry{}
//Счётчик жанров
genresCount := 1
//Область для ввода жанров
moreGenresContainer := container.New(layout.NewVBoxLayout())
//Совокупность полей для ввода тегов
tagsEntry := []*widget.Entry{}
//Счётчик тегов
tagsCount := 1
//Область для ввода тегов
moreTagsContainer := container.New(layout.NewVBoxLayout())
//Вызываем функции для добавления полей ввода жанров и тегов
entriesAndButtonsForGenresAndTags(w, form, genresCount, genresEntry, moreGenresContainer, "More Genres", "Genre")
entriesAndButtonsForGenresAndTags(w, form, tagsCount, tagsEntry, moreTagsContainer, "More Tags", "Tag")
// Создаем таблицу для отображения данных из базы
tableData := [][]string{}
//"Шапка" для таблицы
header := container.NewGridWithColumns(5+10, // 3 для Song, Artist и Album, 10 - для тэгов
widget.NewLabelWithStyle("Song", fyne.TextAlignCenter, fyne.TextStyle{Bold: true, Italic: true}),
widget.NewLabelWithStyle("Artist", fyne.TextAlignCenter, fyne.TextStyle{Bold: true, Italic: true}),
widget.NewLabelWithStyle("Album", fyne.TextAlignCenter, fyne.TextStyle{Bold: true, Italic: true}),
widget.NewLabelWithStyle("Year", fyne.TextAlignCenter, fyne.TextStyle{Bold: true, Italic: true}),
widget.NewLabelWithStyle("Country", fyne.TextAlignCenter, fyne.TextStyle{Bold: true, Italic: true}),
)
tableHeaderForGenresAndTags(header, "Genre %d")
tableHeaderForGenresAndTags(header, "Tag %d")
// Создаем сетку для добавления данных в таблицу
grid := container.New(layout.NewVBoxLayout())
scrollTable := container.NewScroll(container.New(layout.NewGridLayout(5), grid))
scrollTable.SetMinSize(fyne.NewSize(1200, 800))
// Добавляем данные в таблицу
var songs []Song
db.Order("id desc").Find(&songs)
for _, song := range songs {
genres := strings.Split(song.Genres, ", ")
tags := strings.Split(song.Tags, ", ")
rowData := make([]string, 5)
rowData[0] = song.Name
rowData[1] = song.Artist
rowData[2] = song.Album
rowData[3] = song.Year
rowData[4] = song.Country
for i := 0; i < len(genres); i++ {
if len(genres[i]) > 0 {
rowData = append(rowData, genres[i])
}
}
for i := 0; i < len(tags); i++ {
if len(tags[i]) > 0 {
rowData = append(rowData, tags[i])
}
}
tableData = append(tableData, rowData)
}
// Определяем, какие столбцы нужно отобразить в таблице
showColumns := map[int]bool{}
for _, rowData := range tableData {
for i := 5; i < len(rowData); i++ {
if len(rowData[i]) > 0 {
showColumns[i] = true
}
}
}
for _, rowData := range tableData {
row := container.NewGridWithColumns(5+10,
widget.NewLabelWithStyle(rowData[0], fyne.TextAlignCenter, fyne.TextStyle{Bold: true}),
widget.NewLabelWithStyle(rowData[1], fyne.TextAlignCenter, fyne.TextStyle{Bold: true}),
widget.NewLabelWithStyle(rowData[2], fyne.TextAlignCenter, fyne.TextStyle{Bold: true}),
widget.NewLabelWithStyle(rowData[3], fyne.TextAlignCenter, fyne.TextStyle{Bold: true}),
widget.NewLabelWithStyle(rowData[4], fyne.TextAlignCenter, fyne.TextStyle{Bold: true}),
)
for i := 5; i < len(rowData); i++ {
row.Add(widget.NewLabelWithStyle(rowData[i], fyne.TextAlignCenter, fyne.TextStyle{Italic: true}))
}
grid.Add(row)
}
// Обработчик кнопки "Add"
addButton := widget.NewButton("Add", func() {
// Получаем значения из полей ввода
name := form.Items[0].Widget.(*widget.Entry).Text
artist := form.Items[1].Widget.(*widget.Entry).Text
album := form.Items[2].Widget.(*widget.Entry).Text
year := form.Items[3].Widget.(*widget.Entry).Text
country := form.Items[4].Widget.(*widget.Entry).Text
genres := make([]string, 0)
tags := make([]string, 0)
// Обнуляем значения полей ввода
form.Items[0].Widget.(*widget.Entry).SetText("")
form.Items[1].Widget.(*widget.Entry).SetText("")
form.Items[2].Widget.(*widget.Entry).SetText("")
form.Items[3].Widget.(*widget.Entry).SetText("")
form.Items[4].Widget.(*widget.Entry).SetText("")
//Убираем все поля для ввода жанров и тегов
clearTagsAndGenresFields(moreGenresContainer, genresEntry, genres, &genresCount, w)
clearTagsAndGenresFields(moreTagsContainer, tagsEntry, tags, &tagsCount, w)
// Обновляем таблицу
tableData = append(tableData, []string{name, artist, album, year, country})
grid.Objects = make([]fyne.CanvasObject, 0)
for i := range tableData {
grid.Add(widget.NewLabel(tableData[i][0]))
grid.Add(widget.NewLabel(tableData[i][1]))
grid.Add(widget.NewLabel(tableData[i][2]))
grid.Add(widget.NewLabel(tableData[i][3]))
grid.Add(widget.NewLabel(tableData[i][4]))
}
//Добавляем новую запись в базу
db.Create(&Song{
Name: name,
Artist: artist,
Album: album,
Year: year,
Country: country,
Genres: strings.Join(genres, ", "),
Tags: strings.Join(tags, ", "),
})
w.CenterOnScreen()
})
// Создаем вкладки для формы и таблицы
tabs := container.NewAppTabs(
container.NewTabItem("Add Song", container.NewVScroll(container.New(layout.NewVBoxLayout(), form, addButton))),
container.NewTabItem("View Songs", container.New(layout.NewVBoxLayout(), container.NewMax(header), container.NewMax(scrollTable))),
)
// Устанавливаем вкладки на экран
w.SetContent(tabs)
w.ShowAndRun()
}
// Функция для удаления с формы всех полей для ввода жанров и тегов
func clearTagsAndGenresFields(container *fyne.Container, entries []*widget.Entry, tagsOrGenres []string, count *int, w fyne.Window) {
for _, entry := range entries {
tagsOrGenres = append(tagsOrGenres, entry.Text)
entry.SetText("")
}
container.Objects = make([]fyne.CanvasObject, 0)
*count = 1
}
// Функция для добавления на форму полей ввода жанров и тегов
func entriesAndButtonsForGenresAndTags(w fyne.Window, form *widget.Form, count int, entry []*widget.Entry, container *fyne.Container, buttonName string, label string) {
//Обработчик кнопки для добавления новых полей
button := widget.NewButton(buttonName, func() {
if count <= 5 {
count++
//Поле для ввода
newEntry := widget.NewEntry()
entry = append(entry, newEntry)
//Добавляем новое поле для ввода
container.Add((widget.NewLabel(label)))
container.Add(newEntry)
w.CenterOnScreen()
}
})
//Добавляем на форму кнопку для добавления новых полей и область для ввода
form.Append("", button)
form.Append("", container)
}
// Функция для добавления в "шапку" таблицы заголовков столбцов жанров и тегов
func tableHeaderForGenresAndTags(header *fyne.Container, headerText string) {
for i := 0; i < 5; i++ {
header.Add(widget.NewLabelWithStyle(fmt.Sprintf(headerText, i+1), fyne.TextAlignCenter, fyne.TextStyle{Bold: true, Italic: true}))
}
}
Нужно на вкладку View Songs добавить возможность редактирования данных. То есть, чтоб как в экселе: запись прямо в таблице изменил, кнопочку "Сохранить" нажал, всё сохранилось. (Если это вообще как-то можно сделать)