andlabs / ui

Platform-native GUI library for Go.
Other
8.34k stars 647 forks source link

del #350

Open DeadNumbers opened 5 years ago

DeadNumbers commented 5 years ago

del

andlabs commented 5 years ago

This was a legitimate question; the answer is no, because that isn't supported by all the OSs libui runs on. Use a label adjacent tot he progressbar instead.

DeadNumbers commented 5 years ago

@andlabs If using label, my app crashed.

    button.OnClicked(func(*ui.Button) {
        button.Disable()
        i := 0
        go func() {
                for i <= 100 {
                    lab.SetText(fmt.Sprintf("Total: %d", i))
                    i++
                }
                if i >= 100 {
                    button.Enable()
                }
        }()
    })

trace

$ LANG=C go run gui.go
[xcb] Unknown sequence number while processing queue
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
gui: xcb_io.c:263: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.
SIGABRT: abort
PC=0x7f195f00cd7f m=0 sigcode=18446744073709551610
signal arrived during cgo execution

goroutine 1 [syscall, locked to thread]:
runtime.cgocall(0x4ae020, 0xc000044f20, 0xc00009c048)
        /usr/lib/go/src/runtime/cgocall.go:128 +0x5b fp=0xc000044ef0 sp=0xc000044eb8 pc=0x416a7b
github.com/andlabs/ui._Cfunc_uiMain()
        _cgo_gotypes.go:2518 +0x41 fp=0xc000044f20 sp=0xc000044ef0 pc=0x4a1281
github.com/andlabs/ui.Main(0x507008, 0xc000044f88, 0xc000078058)
        /home/user/Go/src/github.com/andlabs/ui/main.go:41 +0xff fp=0xc000044f70 sp=0xc000044f20 pc=0x4a5c1f
main.main()
        /tmp/gui.go:140 +0x2d fp=0xc000044f98 sp=0xc000044f70 pc=0x4ab85d
runtime.main()
        /usr/lib/go/src/runtime/proc.go:200 +0x20c fp=0xc000044fe0 sp=0xc000044f98 pc=0x43df6c
runtime.goexit()
        /usr/lib/go/src/runtime/asm_amd64.s:1337 +0x1 fp=0xc000044fe8 sp=0xc000044fe0 pc=0x465fa1

rax    0x0
rbx    0x6
rcx    0x7f195f00cd7f
rdx    0x0
rdi    0x2
rsi    0x7ffdbf4d3240
rbp    0x7f195f15ceb8
rsp    0x7ffdbf4d3240
r8     0x0
r9     0x7ffdbf4d3240
r10    0x8
r11    0x246
r12    0x7f195ef435d3
r13    0x7f195ef43760
r14    0x107
r15    0x7f195f7439a0
rip    0x7f195f00cd7f
rflags 0x246
cs     0x33
fs     0x0
gs     0x0
exit status 2
bcampbell commented 5 years ago

I think this crash is because you're calling ui calls from another go routine. Look up QueueMain() for a way to do it.

andlabs commented 5 years ago

Yes, that's exactly it.

DeadNumbers commented 5 years ago

Can you add a simple example for using QueueMain?

This not work

package main

import (
    "fmt"
    "time"

    "github.com/andlabs/ui"
)

func setup() {
    win := ui.NewWindow("update label", 300, 200, true)
    win.OnClosing(func(*ui.Window) bool {
        ui.Quit()
        return true
    })
    ui.OnShouldQuit(func() bool {
        win.Destroy()
        return true
    })

    label := ui.NewLabel("this is a label")
    button := ui.NewButton("start")
    button.OnClicked(func(*ui.Button) {

        ui.QueueMain(func() {
            for i := 0; i <= 100; i++ {
                label.SetText(fmt.Sprintf("label: %d", i))
                time.Sleep(10 * time.Millisecond)
            }
        })
    })

    vbox := ui.NewVerticalBox()
    vbox.SetPadded(true)

    grid := ui.NewGrid()
    grid.SetPadded(true)
    grid.Append(button, 0, 0, 1, 1, false, ui.AlignFill, false, ui.AlignFill)
    grid.Append(label, 1, 0, 1, 1, false, ui.AlignFill, false, ui.AlignFill)
    vbox.Append(grid, false)

    win.SetChild(vbox)
    win.Show()
}

func main() {
    ui.Main(setup)
}

изображение

bcampbell commented 5 years ago

How about something like:

button.OnClicked(func(*ui.Button) {
    go func() {
        for i := 0; i <= 100; i++ {
                ui.QueueMain(func() {
                    label.SetText(fmt.Sprintf("label: %d", i))
                })
                time.Sleep(10 * time.Millisecond)
            }
    }()
})

The time.Sleep() is blocking, so you don't want it in the main thread (it'll freeze the GUI), but the label.SetText() must be called from the main thread.

Of course, it'll be a little odd if you click the button before the goroutine finishes - a new goroutine will be spawned, and the two of them will be issues competing SetText() calls on the label. It won't crash because the QueueMain() will make sure they happen one at a time, but the actual label text will be continually jumping between the competing displays.