亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何使用 fyne 避免 GUI 應用程序中的循環依賴?

如何使用 fyne 避免 GUI 應用程序中的循環依賴?

Go
肥皂起泡泡 2022-11-23 16:23:20
我想將 GUI 添加到我用 Go 編寫的命令行應用程序,但我遇到了 fyne 和循環依賴性問題??紤]這個簡單的例子來說明我面臨的問題:假設一個按鈕在我的模型類上觸發了一個耗時的方法(比如獲取數據等)并且我希望視圖在任務完成時更新。我首先實現了一個非常幼稚且完全不解耦的解決方案,這顯然會遇到 go 編譯器引發的循環依賴錯誤。考慮以下代碼:主程序package mainimport (    "my-gui/gui")func main() {    gui.Init()}gui/gui.gopackage guiimport (    "my-gui/model"    //[...] fyne imports)var counterLabel *widget.Labelfunc Init() {    myApp := app.New()    myWindow := myApp.NewWindow("Test")    counterLabel = widget.NewLabel("0")    counterButton := widget.NewButton("Increment", func() {        go model.DoTimeConsumingStuff()    })    content := container.NewVBox(counterLabel, counterButton)    myWindow.SetContent(content)    myWindow.ShowAndRun()}func UpdateCounterLabel(value int) {    if counterLabel != nil {        counterLabel.SetText(strconv.Itoa(value))    }}模型/模型.gopackage modelimport (    "my-gui/gui" // <-- this dependency is where it obviously hits the fan    //[...])var counter = 0func DoTimeConsumingStuff() {    time.Sleep(1 * time.Second)        counter++    fmt.Println("Counter: " + strconv.Itoa(counter))    gui.UpdateCounterLabel(counter)}所以我想知道如何正確解耦這個簡單的應用程序以使其正常工作。我在想什么:使用 fyne 數據綁定:這應該適用于簡單的東西,例如上面示例中的標簽文本。但是,如果我必須根據模型的狀態以非常自定義的方式更新更多內容怎么辦?假設我必須根據模型的條件更新按鈕的啟用狀態。這怎么能綁定到數據呢?這可能嗎?使用標準 MVC 設計模式中的接口:我也嘗試過這個,但無法真正理解它。我創建了一個單獨的模塊,它將提供一個接口,然后可以由模型類導入。然后我會注冊一個視圖(隱式地)實現與模型的接口。但我無法讓它工作。我認為此時我對 go 接口的理解還不夠。短輪詢模型:這只是meh,當然不是 Go 和/或 fyne 的開發人員的意圖:-)任何人都可以指出這個問題的慣用解決方案嗎?我可能在這里遺漏了一些非常非?;镜臇|西......
查看完整描述

1 回答

?
蝴蝶不菲

TA貢獻1810條經驗 獲得超4個贊

返回值

你可以返回值。


func DoTimeConsumingStuff() int {

    time.Sleep(1 * time.Second)

    counter++

    return counter

}

然后在單擊按鈕時生成一個匿名 goroutine,以免阻塞 UI。


counterButton := widget.NewButton("Increment", func() {

    go func() {

        counter := model.DoTimeConsumingStuff(counterChan)

        UpdateCounterLabel(counter)

    }()      

})

打回來

您可以將該UpdateCounterLabel函數傳遞給您的模型函數,也就是回調。


func DoTimeConsumingStuff(callback func(int)) {

    time.Sleep(1 * time.Second)

    counter++

    callback(counter)

}

counterButton := widget.NewButton("Increment", func() {

    go model.DoTimeConsumingStuff(UpdateCounterLabel)

})

渠道

也許您還可以將一個通道傳遞給您的模型函數。但是使用上述方法,這似乎不是必需的。潛在地,如果你有不止一個反價值。


func DoTimeConsumingStuff(counterChan chan int) {

    for i := 0; i < 10; i++ {

        time.Sleep(1 * time.Second)

        counter++

        counterChan <- counter

    }

    close(counterChan)

}

然后在 GUI 中,您可以從通道接收,再次在 goroutine 中,以免阻塞 UI。


counterButton := widget.NewButton("Increment", func() {

    go func() {

        counterChan := make(chan int)

        go model.DoTimeConsumingStuff(counterChan)

        for counter := range counterChan {

            UpdateCounterLabel(counter)

        }

    }()      

})

當然,您也可以再次使用在每次迭代時調用的回調。


查看完整回答
反對 回復 2022-11-23
  • 1 回答
  • 0 關注
  • 169 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號