Go и Fyne - нужен ответ из диалога и включение / отключение кнопки «Отправить» - PullRequest
0 голосов
/ 09 марта 2020

Просто начинаю смотреть на Go и Файн. После написания тестовой программы CRUD с использованием информации, полученной из примеров, мне нужно решить следующее:

  1. Мне нужен начальный диалог или аналогичный, чтобы можно было выбрать существующую запись или «новый "чтобы указать новую запись. Мой существующий диалог не обрабатывает это должным образом.

  2. Мне нужно иметь возможность включить / отключить кнопку Отправить, чтобы разрешить или запретить обновление, если данные не изменились.

  3. Программа компилируется без ошибок, однако "go vet" и VsCode указывают (например, для строки):

     {"Given Names:", arwWidgets[I_NDX_GIVEN]},
 go vet shows:
 ERROR:  "unknown field 'Key' in struct literal of type widget.FormItem",
 however, if I include a key, compiler fails.
Будучи новичком в Go и Fyne, возможно, есть фундаментальные ошибки.

Программа испытаний выглядит следующим образом:

package main
// Dependency: local directory "data".
import (
    "errors"
    "io/ioutil"
    "log"
    "os"
    "strings"

    "fyne.io/fyne"
    "fyne.io/fyne/app"
    "fyne.io/fyne/dialog"
    "fyne.io/fyne/layout"
    "fyne.io/fyne/widget"
)

const BY_SEP byte = byte('|')
const I_ARRAY_LEN int = 10
const I_NDX_GIVEN int = 0
const I_NDX_FAMILY int = 1
const I_NDX_TITLE int = 2
const I_NDX_ADDR1 int = 3
const I_NDX_ADDR2 int = 4
const I_NDX_ADDR3 int = 5
const I_NDX_STATE int = 6
const I_NDX_ZIP int = 7
const I_NDX_TELE1 int = 8
const I_NDX_TELE2 int = 9

var _arsOldData [I_ARRAY_LEN]string
var _arsNewData [I_ARRAY_LEN]string
var _tfDataHasChanged bool
var _sKey string
var _arwEntryWidgets [I_ARRAY_LEN]*widget.Entry
var _wApp fyne.App
var _wWindow fyne.Window
var _wModal widget.PopUp
var _wFormKeyEntry widget.Form

//-------------------------------------------------------------------------------

func main() {
    log.Println("In fytest01")
    _, err := os.Stat("./data/")
    if err != nil {
        log.Println("You need to create directory: 'data'")
        os.Exit(1)
    }
    //fnReadData()
    _wApp := app.New()
    _wWindow := _wApp.NewWindow("Customer Details")
    //_wFormKeyEntry := fnCreateKeyForm()
    wFormMain := fnCreateMainForm()
    //_wModal := widget.NewModalPopUp(_wFormKeyEntry, _wWindow.Canvas())
    _wWindow.Resize(fyne.NewSize(500, 400))
    _wWindow.CenterOnScreen()
    _wWindow.SetContent(widget.NewVBox(
        wFormMain,
        widget.NewGroup("",
            fyne.NewContainerWithLayout(layout.NewGridLayout(2),
                widget.NewButton("Exit", func() {
                    _wApp.Quit()
                }),
                widget.NewButton("Submit", func() {
                    log.Println("Submit button pressed")
                    err := fnUpdateData()
                    if err == nil {
                        dialog.ShowInformation("Information", "Data was updated", _wWindow)
                        wEntryForKey := widget.NewEntry()
                        wEntryForKey.SetPlaceHolder("Enter Key (4) : ")
                        wEntryForKey.OnChanged = func(sKey string) {
                            log.Println("Entered", sKey)
                            if len(sKey) == 4 {
                                _sKey = sKey
                            }
                            if len(_sKey) == 4 {
                                dialog.ShowInformation("Information", "Key "+_sKey+" has been entered - press OK", _wWindow)
                                fnReadData()
                                fnRefreshWidgetData()
                            }
                        }
                        dialog.ShowCustom("Enter Customer Key", "OK", wEntryForKey, _wWindow)
                    } else {
                        dialog.ShowError(err, _wWindow)
                    }
                }),
            ))),
    )
    //fnShowKeyEntryDialog()

    wEntryForKey := widget.NewEntry()
    wEntryForKey.SetPlaceHolder("Enter Key (4) : ")
    wEntryForKey.OnChanged = func(sKey string) {
        log.Println("Entered", sKey)
        if len(sKey) == 4 {
            _sKey = sKey
        }
        if len(_sKey) == 4 {
            dialog.ShowInformation("Information", "Key "+_sKey+" has been entered - press OK", _wWindow)
            fnReadData()
            fnRefreshWidgetData()
        }
    }
    dialog.ShowCustom("Enter Customer Key", "OK", wEntryForKey, _wWindow)
    _wWindow.ShowAndRun()
    //_wModal.Show()
}

//-------------------------------------------------------------------------------

func fnCreateAllEntryWidgets() {
    _arwEntryWidgets[I_NDX_GIVEN] = fnCreateSingleEntryWidget(I_NDX_GIVEN)
    _arwEntryWidgets[I_NDX_FAMILY] = fnCreateSingleEntryWidget(I_NDX_FAMILY)
    _arwEntryWidgets[I_NDX_TITLE] = fnCreateSingleEntryWidget(I_NDX_TITLE)
    _arwEntryWidgets[I_NDX_ADDR1] = fnCreateSingleEntryWidget(I_NDX_ADDR1)
    _arwEntryWidgets[I_NDX_ADDR2] = fnCreateSingleEntryWidget(I_NDX_ADDR2)
    _arwEntryWidgets[I_NDX_ADDR3] = fnCreateSingleEntryWidget(I_NDX_ADDR3)
    _arwEntryWidgets[I_NDX_STATE] = fnCreateSingleEntryWidget(I_NDX_STATE)
    _arwEntryWidgets[I_NDX_ZIP] = fnCreateSingleEntryWidget(I_NDX_ZIP)
    _arwEntryWidgets[I_NDX_TELE1] = fnCreateSingleEntryWidget(I_NDX_TELE1)
    _arwEntryWidgets[I_NDX_TELE2] = fnCreateSingleEntryWidget(I_NDX_TELE2)
}

//-------------------------------------------------------------------------------

func fnCreateSingleEntryWidget(iNdxData int) *widget.Entry {
    wEntry := widget.NewEntry()
    wEntry.SetText(_arsOldData[iNdxData])
    wEntry.OnChanged = func(sText string) {
        _arsNewData[iNdxData] = sText
        fnCheckIfDataHasChanged()
    }
    return wEntry
}

//-------------------------------------------------------------------------------

func fnCreateFormFields(arwWidgets [I_ARRAY_LEN]*widget.Entry) []*widget.FormItem {
    return []*widget.FormItem{
        {"Given Names:", arwWidgets[I_NDX_GIVEN]},
        {"Family Name: ", arwWidgets[I_NDX_FAMILY]},
        {"Title: ", arwWidgets[I_NDX_TITLE]},
        {"Address Ln 1: ", arwWidgets[I_NDX_ADDR1]},
        {"   ''   Ln 2: ", arwWidgets[I_NDX_ADDR2]},
        {"   ''   Ln 3: ", arwWidgets[I_NDX_ADDR3]},
        {"   ''   State ", arwWidgets[I_NDX_STATE]},
        {"   ''   Zip: ", arwWidgets[I_NDX_ZIP]},
        {"Telephone 1: ", arwWidgets[I_NDX_TELE1]},
        {"Telephone 2: ", arwWidgets[I_NDX_TELE2]},
    }
}

//-------------------------------------------------------------------------------

func fnCheckIfDataHasChanged() {
    var tfChanged bool = false
    for iNdxData := 0; !tfChanged && iNdxData < len(_arsOldData); iNdxData++ {
        tfChanged = (_arsNewData[iNdxData] != _arsOldData[iNdxData])
    }
    if tfChanged != _tfDataHasChanged {
        _tfDataHasChanged = tfChanged
        if tfChanged {
            //  COULD NOT CREATE _wBtnSubmitMain AS A GLOBAL VARIABLE.
            //_wBtnSubmitMain.Show()
            //_wBtnSubmitMain.Enable()
        } else {
            //_wBtnSubmitMain.Disable()
            //_wBtnSubmitMain.Hide()
        }
    }
}

//-------------------------------------------------------------------------------

func fnReadData() {
    _tfDataHasChanged = false
    log.Println("fnReadData: Key = " + _sKey)
    var sData string
    if len(_sKey) > 0 {
        arbData, _ := ioutil.ReadFile("./data/" + _sKey)
        if arbData != nil {
            sData = string(arbData)
        }
    }
    log.Println("fnReadData: sData = " + sData)

    /* CLEAR OLD DATA */
    for iNdxData := 0; iNdxData < I_ARRAY_LEN; iNdxData++ {
        _arsOldData[iNdxData] = ""
    }

    /* POPULATE DATA IF ANY */
    var iNdx1 int = 0
    var iNdxData int = 0
    var iLen int = len(sData)
    for iNdx2 := 0; iNdx2 < len(sData); iNdx2++ {
        if sData[iNdx2] == BY_SEP {
            _arsOldData[iNdxData] = sData[iNdx1:iNdx2]
            iNdx1 = iNdx2 + 1
            iNdxData++
        } else if iNdx2 == (iLen - 1) {
            _arsOldData[iNdxData] = sData[iNdx1 : iNdx2+1]
        }
    }
    for iNdx := 0; iNdx < I_ARRAY_LEN; iNdx++ {
        _arsNewData[iNdx] = _arsOldData[iNdx]
    }
}

//-------------------------------------------------------------------------------

func fnUpdateData() error {
    if !_tfDataHasChanged {
        return errors.New("Data has not changed")
    }

    if len(_sKey) < 1 {
        _sKey = "9999"
        //dialog.ShowInformation("Information", "Default key of 9999 was used", _wWindow)  // CAUSES ERROR
    }

    var sNewData string = ""
    for iNdxData, sVal := range _arsNewData {
        if strings.Index(sVal, "|") >= 0 {
            sVal = strings.ReplaceAll(sVal, "|", ":")
        }
        if iNdxData != I_ARRAY_LEN-1 {
            sNewData += sVal + string(BY_SEP)
        } else {
            sNewData += sVal
        }
    }
    log.Println("New Data = " + sNewData)
    var err error = ioutil.WriteFile("./data/"+_sKey, []byte(sNewData), 0644)
    if err == nil {
        for iNdxData := 0; iNdxData < len(_arsNewData); iNdxData++ {
            _arsOldData[iNdxData] = _arsNewData[iNdxData]
        }
        fnCheckIfDataHasChanged()
    }
    return err
}

//-------------------------------------------------------------------------------

func fnCreateKeyForm() *widget.Form {
    wEntryKey := widget.NewEntry()
    return &widget.Form{
        Items: []*widget.FormItem{
            {"Key:", wEntryKey}},
        OnSubmit: func() {
            _sKey = wEntryKey.Text
            log.Println("Key = " + _sKey)
            fnReadData()
            log.Println("Data has been read")
            fnRefreshWidgetData()
            _wFormKeyEntry.Hide()
            //_wModal.Hide()
        },
    }
}

//-------------------------------------------------------------------------------

//func fnCreateMainWindow() {
//  log.Println("Creating Main Window   Form")
//  wFormMain := fnCreateMainForm()
//  log.Println("Creating Main Window   Window")
//  _wWindow.SetContent( //widget.NewVBox(
//      wFormMain,
//  )
//}

//-------------------------------------------------------------------------------

func fnCreateMainForm() *widget.Form {
    log.Println("Create form1 widgets")
    fnCreateAllEntryWidgets()
    log.Println("Create form1 FormFields")
    arwFormFields := fnCreateFormFields(_arwEntryWidgets)
    log.Println("Creating Form1")
    return &widget.Form{
        Items: arwFormFields,
    }
}

//-------------------------------------------------------------------------------

func fnRefreshWidgetData() {
    for iNdx := 0; iNdx < I_ARRAY_LEN; iNdx++ {
        _arwEntryWidgets[iNdx].SetText(_arsNewData[iNdx])
    }
}

1 Ответ

0 голосов
/ 09 марта 2020
  1. Вы можете просто добавить кнопку «Новый» в стартовое окно, которое заполняет значения по умолчанию, а затем открывает главное окно. Имеет ли это смысл?

  2. Вы создаете кнопку Отправить, создавая и передавая ее непосредственно SetContent. Вам нужно сохранить его в переменной, чтобы в какой-то момент вы могли вызвать Disable().

submitButton := widget.NewButton("Submit", func() {
    log.Println("Submit button pressed")
...
})
_wWindow.SetContent(widget.NewVBox(
    wFormMain,
    widget.NewGroup("",
        fyne.NewContainerWithLayout(layout.NewGridLayout(2),
            widget.NewButton("Exit", func() {
                _wApp.Quit()
            }),
            submitButton,
        ))),
)

...
if dataChanged {
    submitButton.Enable()
} else {
    submitButton.Disable()
}
Я думаю, что в сообщении go vet говорится, что вы должны назвать все поля в вашем struct literal (хотя я получаю другое сообщение для вас, используя Go 1.13). Go позволяет добавлять значения по порядку или по имени - go vet говорит вам, что по имени безопаснее (например, если поля перемещены или вставлены в структуру FormItem, ваш код будет нарушен).

Ie:

    return []*widget.FormItem{
        { Text: "Given Names:", Widget: arwWidgets[I_NDX_GIVEN]},
...
Также это может упростить вещи, чтобы поместить все ваши глобальные переменные в структуру, и тогда вы можете иметь «методы» в структуре. (Есть несколько причин, чтобы избежать глобальных переменных, о которых вы, вероятно, уже знаете. Я ценю, что это, вероятно, началось как простой тест, который вырос, но это может быть хорошее время для рефакторинга.)
...