Вопрос к знатокам 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 добавить возможность редактирования данных. То есть, чтоб как в экселе: запись прямо в таблице изменил, кнопочку "Сохранить" нажал, всё сохранилось. (Если это вообще как-то можно сделать)


Ответы (0 шт):