[GH-ISSUE #136] OnRun()? #107

Closed
opened 2026-03-04 01:01:59 +03:00 by kerem · 8 comments
Owner

Originally created by @undeadindustries on GitHub (Jul 2, 2018).
Original GitHub issue: https://github.com/rivo/tview/issues/136

Is there a way to run a func when Run is called?

For example, my app needs to load many files into memory. I want it to start doing that before loading anything else, while displaying a spinner modal... I'd rather not have to have the user press or click anything for it to load these files.

I realize I could just load the files before .Run() but the user would just be waiting before any Box popped up...

Thanks!

Originally created by @undeadindustries on GitHub (Jul 2, 2018). Original GitHub issue: https://github.com/rivo/tview/issues/136 Is there a way to run a func when Run is called? For example, my app needs to load many files into memory. I want it to start doing that before loading anything else, while displaying a spinner modal... I'd rather not have to have the user press or click anything for it to load these files. I realize I could just load the files before .Run() but the user would just be waiting before any Box popped up... Thanks!
kerem closed this issue 2026-03-04 01:02:00 +03:00
Author
Owner

@rivo commented on GitHub (Jul 3, 2018):

I'm not completely sure I understand your request. Are you talking about the Application's Run() method? That method is typically only called once at the very beginning of your program. Nothing from tview is displayed before you call this function. You can run your function immediately before Run() or you can start it in parallel in a goroutine.

If you want to show some state during the loading of your files without allowing the user to interact with the application, you'll want to use Pages. Create a page with your state (e.g. A TextView with the text "Loading (80%)..."). When loading has finished, you switch to a page that contains the elements of your application.

If you want your application's elements to be visible already, you can also place a modal on top of them with the loading progress information. Here is some documentation on how to work with modals.

Does this answer your question?

<!-- gh-comment-id:402082961 --> @rivo commented on GitHub (Jul 3, 2018): I'm not completely sure I understand your request. Are you talking about the `Application`'s [`Run()`](https://godoc.org/github.com/rivo/tview#Application.Run) method? That method is typically only called once at the very beginning of your program. Nothing from `tview` is displayed before you call this function. You can run your function immediately before `Run()` or you can start it in parallel in a goroutine. If you want to show some state during the loading of your files without allowing the user to interact with the application, you'll want to use [`Pages`](https://godoc.org/github.com/rivo/tview#Pages). Create a page with your state (e.g. A `TextView` with the text "Loading (80%)..."). When loading has finished, you switch to a page that contains the elements of your application. If you want your application's elements to be visible already, you can also place a modal on top of them with the loading progress information. [Here](https://github.com/rivo/tview/wiki/Modal) is some documentation on how to work with modals. Does this answer your question?
Author
Owner

@undeadindustries commented on GitHub (Jul 3, 2018):

Thank you for your reply.

Let me rephrase the question.

I need these files to open without the user having to press a button. I also want to load a spinner (page, modal, whatever) ...

So I was wondering how I could run a function when Focus() is run on an element. So the page would get focus and start loading these files.

Thanks!

<!-- gh-comment-id:402142039 --> @undeadindustries commented on GitHub (Jul 3, 2018): Thank you for your reply. Let me rephrase the question. I need these files to open without the user having to press a button. I also want to load a spinner (page, modal, whatever) ... So I was wondering how I could run a function when Focus() is run on an element. So the page would get focus and start loading these files. Thanks!
Author
Owner

@rivo commented on GitHub (Jul 4, 2018):

I'm still not sure why you would need to hook into Focus(). I wrote up a quick example of how I understand your request and how I'd solve it:

package main

import (
	"fmt"
	"time"

	"github.com/rivo/tview"
)

var app *tview.Application

func main() {
	pages := tview.NewPages()

	mainElements := tview.NewTextView().
		SetText("Files have been loaded").
		SetTextAlign(tview.AlignCenter)
	mainElements.SetTitle("Main application").
		SetBorder(true)
	pages.AddAndSwitchToPage("main", mainElements, true)

	app = tview.NewApplication()

	loadFiles(pages)

	if err := app.SetRoot(pages, true).Run(); err != nil {
		panic(err)
	}
}

func loadFiles(pages *tview.Pages) {
	progress := tview.NewTextView().SetText("Loading files...").SetTextAlign(tview.AlignCenter)
	progress.SetBorder(true)
	pages.AddAndSwitchToPage("loading", progress, true)

	go func() {
		// Simulate loading files with the time.Sleep() function.
		for file := 0; file < 10; file++ {
			time.Sleep(time.Second)
			fmt.Fprint(progress, ".")
			app.Draw()
		}
		pages.SwitchToPage("main")
		app.Draw()
		// We need to call app.Draw() because we're in a goroutine.
	}()
}

Does this do what you need?

<!-- gh-comment-id:402374013 --> @rivo commented on GitHub (Jul 4, 2018): I'm still not sure why you would need to hook into `Focus()`. I wrote up a quick example of how I understand your request and how I'd solve it: ```go package main import ( "fmt" "time" "github.com/rivo/tview" ) var app *tview.Application func main() { pages := tview.NewPages() mainElements := tview.NewTextView(). SetText("Files have been loaded"). SetTextAlign(tview.AlignCenter) mainElements.SetTitle("Main application"). SetBorder(true) pages.AddAndSwitchToPage("main", mainElements, true) app = tview.NewApplication() loadFiles(pages) if err := app.SetRoot(pages, true).Run(); err != nil { panic(err) } } func loadFiles(pages *tview.Pages) { progress := tview.NewTextView().SetText("Loading files...").SetTextAlign(tview.AlignCenter) progress.SetBorder(true) pages.AddAndSwitchToPage("loading", progress, true) go func() { // Simulate loading files with the time.Sleep() function. for file := 0; file < 10; file++ { time.Sleep(time.Second) fmt.Fprint(progress, ".") app.Draw() } pages.SwitchToPage("main") app.Draw() // We need to call app.Draw() because we're in a goroutine. }() } ``` Does this do what you need?
Author
Owner

@undeadindustries commented on GitHub (Jul 4, 2018):

Thanks. That looks like it could work. Thanks!

<!-- gh-comment-id:402508325 --> @undeadindustries commented on GitHub (Jul 4, 2018): Thanks. That looks like it could work. Thanks!
Author
Owner

@smazurov commented on GitHub (Jul 13, 2018):

@rivo I just wanted to say thanks! Im jumping back into go to write a console app, and your project, responsiveness and code cleanliness is hugely appreciated. Can't thank you enough.

<!-- gh-comment-id:404971426 --> @smazurov commented on GitHub (Jul 13, 2018): @rivo I just wanted to say thanks! Im jumping back into go to write a console app, and your project, responsiveness and code cleanliness is hugely appreciated. Can't thank you enough.
Author
Owner

@rivo commented on GitHub (Jul 14, 2018):

Thank you! I really appreciate it.

<!-- gh-comment-id:405015392 --> @rivo commented on GitHub (Jul 14, 2018): Thank you! I really appreciate it.
Author
Owner

@mjgarton commented on GitHub (Jul 20, 2018):

The example here is racy. If you remove the sleep and try it with the race detector enabled, it fires fairly reliably.

Here is one example.

==================
WARNING: DATA RACE
Read at 0x00c420138000 by main goroutine:
  github.com/rivo/tview.(*Box).Draw()
      /home/mgarton/gopath/src/github.com/rivo/tview/box.go:228 +0x149e
  github.com/rivo/tview.(*Pages).Draw()
      /home/mgarton/gopath/src/github.com/rivo/tview/pages.go:237 +0x7e
  github.com/rivo/tview.(*Application).Draw()
      /home/mgarton/gopath/src/github.com/rivo/tview/application.go:258 +0x135
  github.com/rivo/tview.(*Application).Run()
      /home/mgarton/gopath/src/github.com/rivo/tview/application.go:102 +0x179
  main.main()
      /tmp/asd.go:25 +0x80c

Previous write at 0x00c420138000 by goroutine 7:
  github.com/rivo/tview.(*Pages).SetRect()
      /home/mgarton/gopath/src/github.com/rivo/tview/box.go:113 +0x5f
  github.com/rivo/tview.(*Application).Draw()
      /home/mgarton/gopath/src/github.com/rivo/tview/application.go:246 +0x226
  main.loadFiles.func1()
      /tmp/asd.go:40 +0xbe

Goroutine 7 (running) created at:
  main.loadFiles()
      /tmp/asd.go:35 +0x49f
  main.main()
      /tmp/asd.go:23 +0x7c3
==================
==================
<!-- gh-comment-id:406633793 --> @mjgarton commented on GitHub (Jul 20, 2018): The example here is racy. If you remove the sleep and try it with the race detector enabled, it fires fairly reliably. Here is one example. ``` ================== WARNING: DATA RACE Read at 0x00c420138000 by main goroutine: github.com/rivo/tview.(*Box).Draw() /home/mgarton/gopath/src/github.com/rivo/tview/box.go:228 +0x149e github.com/rivo/tview.(*Pages).Draw() /home/mgarton/gopath/src/github.com/rivo/tview/pages.go:237 +0x7e github.com/rivo/tview.(*Application).Draw() /home/mgarton/gopath/src/github.com/rivo/tview/application.go:258 +0x135 github.com/rivo/tview.(*Application).Run() /home/mgarton/gopath/src/github.com/rivo/tview/application.go:102 +0x179 main.main() /tmp/asd.go:25 +0x80c Previous write at 0x00c420138000 by goroutine 7: github.com/rivo/tview.(*Pages).SetRect() /home/mgarton/gopath/src/github.com/rivo/tview/box.go:113 +0x5f github.com/rivo/tview.(*Application).Draw() /home/mgarton/gopath/src/github.com/rivo/tview/application.go:246 +0x226 main.loadFiles.func1() /tmp/asd.go:40 +0xbe Goroutine 7 (running) created at: main.loadFiles() /tmp/asd.go:35 +0x49f main.main() /tmp/asd.go:23 +0x7c3 ================== ================== ```
Author
Owner

@rivo commented on GitHub (Jul 27, 2018):

Thanks @mjgarton. I thought I had this one covered but I was wrong. Draw() is now thread-safe.

I found another race condition but it's part of tcell. I should probably submit an issue at some point.

<!-- gh-comment-id:408436833 --> @rivo commented on GitHub (Jul 27, 2018): Thanks @mjgarton. I thought I had this one covered but I was wrong. `Draw()` is now thread-safe. I found another race condition but it's part of [`tcell`](https://github.com/gdamore/tcell). I should probably submit an issue at some point.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/tview#107
No description provided.