google / gxui

An experimental Go cross platform UI library.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

panic when change label text in linelayout by goroutine

zhangpy opened this issue · comments

panic: Cannot call Relayout() while in LayoutChildren

goroutine 7 [running]:
github.com/google/gxui/mixins/parts.(*Layoutable).Relayout(0xc2081d9790)
    src/github.com/google/gxui/mixins/parts/layoutable.go:67 +0x72
github.com/google/gxui/mixins/parts.(*Layoutable).Relayout(0xc20824a3a0)
    src/github.com/google/gxui/mixins/parts/layoutable.go:72 +0xcc
github.com/google/gxui/mixins.(*Label).SetText(0xc20824a240, 0x7fe070, 0x1)
    src/github.com/google/gxui/mixins/label.go:52 +0xd8
main.func·002()
    src/zz/words2/test/main.go:45 +0xd5
created by main.appMain
    src/zz/words2/test/main.go:47 +0x69a

package main

import (
    "math/rand"
    "time"
    "zz/words2/gxfont"

    "github.com/google/gxui"
    "github.com/google/gxui/drivers/gl"
    "github.com/google/gxui/themes/dark"
)

func appMain(driver gxui.Driver) {
    theme := dark.CreateTheme(driver)

    font, err := driver.CreateFont(gxfont.Default, 500)
    if err != nil {
        panic(err)
    }

    window := theme.CreateWindow(1024, 800, "Hi")
    window.SetBackgroundBrush(gxui.CreateBrush(gxui.Gray50))

    cs := []string{"a", "1", "b", "2", "c", "3", "d", "4"}

    layout := theme.CreateLinearLayout()
    layout.SetSizeMode(gxui.Fill)
    layout.SetDirection(gxui.RightToLeft)

    label1 := theme.CreateLabel()
    label1.SetFont(font)
    changeFont1Chan := make(chan int)
    go func() {
        for {
            <-changeFont1Chan
            label1.SetText(cs[rand.Intn(len(cs))])
        }
    }()
    label2 := theme.CreateLabel()
    label2.SetFont(font)
    changeFont2Chan := make(chan int)
    go func() {
        for {
            <-changeFont2Chan
            label2.SetText(cs[rand.Intn(len(cs))])
        }
    }()
    changeFontChan := make(chan int)
    go func() {
        for {
            <-changeFontChan
            changeFont1Chan <- 1
            changeFont2Chan <- 1
        }
    }()

    layout.AddChild(label1)
    layout.AddChild(label2)
    window.AddChild(layout)

    window.OnClose(driver.Terminate)

    window.OnKeyDown(func(e gxui.KeyboardEvent) {
        switch e.Key {
        case gxui.KeyLeft:
            changeFontChan <- 1
        case gxui.KeyRight:
            changeFontChan <- 1
        }
    })

    //simulate user's action like press keyboard to trigger this change.
    //it is more easy to trigger the panic with shorter sleep time.
    go func() {
        for {
            changeFontChan <- 1
            time.Sleep(time.Second)
        }
    }()
}

func main() {
    gl.StartDriver(appMain)
}

Your problem here is with the goroutines calling SetText. GXUI does not support calls directly from goroutines other than the goroutine that executes the gl.StartDriver callback. You can however use the Driver.Call method to execute your UI code on the correct goroutine:

    go func() {
        for {
            <-changeFont1Chan
            driver.Call(func() {
                label1.SetText(cs[rand.Intn(len(cs))])
            })
        }
    }()