Почему бы не изменить отображение индикатора выполнения в gxui?

Я хотел использовать индикатор прогресса из gxui, но получил не то, что ожидал. Пример работает как надо, но изменить его у меня не получилось. Вот код:

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "time"

    "github.com/google/gxui"
    "github.com/google/gxui/drivers/gl"
    "github.com/google/gxui/math"
    "github.com/google/gxui/samples/flags"
)

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

    layout := theme.CreateLinearLayout()
    layout.SetHorizontalAlignment(gxui.AlignCenter)

    progressBar := theme.CreateProgressBar()
    progressBar.SetDesiredSize(math.Size{W: 480, H: 60})

    button := theme.CreateButton()
    button.SetText("Start")
    t0 := time.Now()
    button.OnClick(func(gxui.MouseEvent) {
        progressBar.SetTarget(100)
        N := 100

        for count := 0; count < N; count++ {
            resp, err := http.Get("http://example.com")
            if err != nil {
                log.Fatal(err)
            }
            defer resp.Body.Close()

            if count%10 == 0 {

                go func() {
                    driver.Call(func() {
                        fmt.Println("Tuk")
                        progressBar.SetProgress(count * 100 / N)
                    })
                }()
                fmt.Println(count)
                fmt.Println(ioutil.ReadAll(resp.Body))
                fmt.Printf("Elapsed time: %v\n", time.Since(t0))
            }
        }
        progressBar.SetProgress(50)
    })

    layout.AddChild(button)
    layout.AddChild(progressBar)

    window := theme.CreateWindow(500, 100, "Test")
    window.SetScale(flags.DefaultScaleFactor)
    window.AddChild(layout)
    window.OnClose(driver.Terminate)
}

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

Так как я использовал goroutine, предполагается, что выходной текст будет чередоваться, но все goroutine выполняли печать только после основного потока. Что я делаю не так и как это исправить?

1 ответ

Решение

Разница в том, что ваша программа входит в очередь, выполняющую подпрограмму пользовательского интерфейса, как написано в документации:

// Вызываем очереди f, которые будут выполняться в go-подпрограмме пользовательского интерфейса, и возвращаются до вызова f.

UI-подпрограмма выполняет цикл, поэтому не может одновременно обрабатывать изменения ленты ProgressBar. Чтобы получить желаемый результат, необходимо запустить функцию обработки в отдельной программе. Модифицированный код:

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "time"

    "github.com/google/gxui"
    "github.com/google/gxui/drivers/gl"
    "github.com/google/gxui/math"
    "github.com/google/gxui/samples/flags"
)

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

    layout := theme.CreateLinearLayout()
    layout.SetHorizontalAlignment(gxui.AlignCenter)

    progressBar := theme.CreateProgressBar()
    progressBar.SetDesiredSize(math.Size{W: 480, H: 60})
    progressBar.SetTarget(100)
    button := theme.CreateButton()
    button.SetText("Start")
    t0 := time.Now()
    button.OnClick(func(gxui.MouseEvent) {
        go func() {
            N := 100
            for count := 0; count < N; count++ {
                resp, err := http.Get("http://example.com")
                if err != nil {
                    log.Fatal(err)
                }
                defer resp.Body.Close()

                driver.Call(func() {
                    progressBar.SetProgress(count * 100 / N)
                })

                fmt.Println(count)
                fmt.Println(ioutil.ReadAll(resp.Body))
                fmt.Printf("Elapsed time: %v\n", time.Since(t0))

            }
            progressBar.SetTarget(100)
        }()
    })

    layout.AddChild(button)
    layout.AddChild(progressBar)

    window := theme.CreateWindow(500, 100, "Test")
    window.SetScale(flags.DefaultScaleFactor)
    window.AddChild(layout)
    window.OnClose(driver.Terminate)

}

func main() {
    gl.StartDriver(appMain)
}
Другие вопросы по тегам