visualfc / atk

Another Golang Tcl/Tk binding GUI ToolKit
GNU Lesser General Public License v2.1
97 stars 19 forks source link

用go程去刷下控件内容没有作用 #19

Closed 52LY closed 3 years ago

52LY commented 3 years ago

代码如下:

package main

import "github.com/visualfc/atk/tk"
import "strings"
import "strconv"
import "time"
import "fmt"

type Window struct { *tk.Window }

func f1(x float64) float64 {
   return x * x - x
}

func integrate_f1(a, b  float64, N int) float64 {
   // 0 23 10000000001
   var s float64 = 0
   dx := (b - a) / float64(N)

   for i:=0; i<N; i++ {
       s += f1(a + float64(i) * dx)
   }

   return s * dx
}

func cal(input string, resch chan string) {
    start := time.Now()

    inputnum := strings.Split(input," ")
    a,_ := strconv.ParseFloat(inputnum[0], 64)
    b,_ := strconv.ParseFloat(inputnum[1], 64)
    N,_ := strconv.Atoi(inputnum[2])
    res := integrate_f1(a, b, N)

    end := time.Now()

    delta := end.Sub(start)

    resch <- fmt.Sprintf("计算结果: \nres is %v \ntime: %s", res, delta)

}

func NewWindow() *Window {

    s1 := make(chan string)

    mw := &Window{}
    mw.Window = tk.RootWindow()

    labelf := tk.NewLabel(mw, "计算阻塞")
    entryf := tk.NewEntry(mw,)
    labels := tk.NewLabel(mw, "计算结果: ")
    btn1 := tk.NewButton(mw,"开始计算",tk.WidgetAttrInitUseTheme(true))
    btn2 := tk.NewButton(mw,"退出",tk.WidgetAttrInitUseTheme(true))

    btn1.SetTakeFocus(false)
    btn2.SetTakeFocus(false)

    // go运行耗时函数,然后go刷新label控件内容,但是内容没有刷新
    // labels.SetText(<-s1)这样的话可以刷新,但是界面会阻塞
    // go func() { fmt.Println(<-s1) }() 这样打印结果也没问题,界面不会阻塞
    btn1.OnCommand(func() { 
        go cal(entryf.Text(),s1)
        go func() { labels.SetText(<-s1) }()
    })

    btn2.OnCommand(func() { tk.Quit() })

    vbox := tk.NewVPackLayout(mw)
    vbox.SetPaddingN(5, 5)
    vbox.AddWidgetEx(labelf, 0, false, 6)
    vbox.AddWidgetEx(entryf, 0, false, 6)
    vbox.AddWidgetEx(labels, 0, false, 6)
    vbox.AddWidgetEx(btn1, 0, false, 6)
    vbox.AddWidgetEx(btn2, 0, false, 6)

    return mw
}

func main() {
    win := func() {
        mw := NewWindow()
        mw.SetTitle("阻塞窗口例子")
        mw.ResizeN(600, 600)
        mw.Center(nil)
        mw.ShowNormal()
    }

    tk.MainLoop(win)
}
visualfc commented 3 years ago

一个原则是永远不要在 go func() 中 直接对 UI 进行读和写,需要时可以使用 tk.Async 函数

btn1.OnCommand(func() {
    in := entryf.Text() 
       // 先从 ui 中获取值,再运行 go func
    go cal(in, s1)
    go func() {
        out := <-s1
                // 先获取值,再通过 Async 对 ui 读写
        tk.Async(func() {
            labels.SetText(out) 
        })
    }()
})
52LY commented 3 years ago

感谢