[GH-ISSUE #198] Need help for showing two modal #156

Closed
opened 2026-03-04 01:02:27 +03:00 by kerem · 4 comments
Owner

Originally created by @thedevsaddam on GitHub (Nov 29, 2018).
Original GitHub issue: https://github.com/rivo/tview/issues/198

I want to show two modal, the first modal with a message and after doing some task another modal:

Code


package main

import (
	"time"

	"github.com/rivo/tview"
)

func main() {
	app := tview.NewApplication()

	pages := tview.NewPages()

	frmLogin := tview.NewForm().
		AddButton("Button A", func() {
			tv1 := tview.NewModal().SetText("Please wait...")
			pages.AddPage("modal1", tv1, true, true) // add modal page
			// I WANT TO DO SOME TASK HERE...
			time.Sleep(2 * time.Second)
			// pages.HidePage("modal1") //"hide Waiting modal"
			// TASK DONE...
			tv2 := tview.NewModal().
				SetText("Tank you for patient!").
				AddButtons([]string{"Okay"}).
				SetDoneFunc(func(buttonIndex int, buttonLabel string) {
					if buttonLabel == "Okay" {
						pages.SwitchToPage("formA")
					}
				})
			pages.AddPage("modal2", tv2, true, true) // add modal page
		}).
		AddButton("Quit", func() {
			app.Stop()
		})

	frmLogin.SetBorder(true).SetTitle("Demo Page").SetTitleAlign(tview.AlignCenter)
	pages.AddPage("formA", frmLogin, true, true)

	// run the app root tree
	if err := app.SetRoot(pages, true).SetFocus(pages).Run(); err != nil {
		panic(err)
	}
}

Originally created by @thedevsaddam on GitHub (Nov 29, 2018). Original GitHub issue: https://github.com/rivo/tview/issues/198 I want to show two modal, the first modal with a message and after doing some task another modal: Code ```go package main import ( "time" "github.com/rivo/tview" ) func main() { app := tview.NewApplication() pages := tview.NewPages() frmLogin := tview.NewForm(). AddButton("Button A", func() { tv1 := tview.NewModal().SetText("Please wait...") pages.AddPage("modal1", tv1, true, true) // add modal page // I WANT TO DO SOME TASK HERE... time.Sleep(2 * time.Second) // pages.HidePage("modal1") //"hide Waiting modal" // TASK DONE... tv2 := tview.NewModal(). SetText("Tank you for patient!"). AddButtons([]string{"Okay"}). SetDoneFunc(func(buttonIndex int, buttonLabel string) { if buttonLabel == "Okay" { pages.SwitchToPage("formA") } }) pages.AddPage("modal2", tv2, true, true) // add modal page }). AddButton("Quit", func() { app.Stop() }) frmLogin.SetBorder(true).SetTitle("Demo Page").SetTitleAlign(tview.AlignCenter) pages.AddPage("formA", frmLogin, true, true) // run the app root tree if err := app.SetRoot(pages, true).SetFocus(pages).Run(); err != nil { panic(err) } } ```
kerem closed this issue 2026-03-04 01:02:28 +03:00
Author
Owner

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

The reason you don't see the first modal is that the screen is not automatically redrawn when you call pages.AddPage().

I've added Application.ForceDraw() in the latest commit and you should call it after adding the first modal so it is shown to the user.

Note that it gets more complicated if you use goroutines. For those scenarios, check out the Wiki.

<!-- gh-comment-id:443651313 --> @rivo commented on GitHub (Dec 3, 2018): The reason you don't see the first modal is that the screen is not automatically redrawn when you call `pages.AddPage()`. I've added [`Application.ForceDraw()`](https://godoc.org/github.com/rivo/tview#Application.ForceDraw) in the latest commit and you should call it after adding the first modal so it is shown to the user. Note that it gets more complicated if you use goroutines. For those scenarios, check out the [Wiki](https://github.com/rivo/tview/wiki/Concurrency).
Author
Owner

@thedevsaddam commented on GitHub (Dec 3, 2018):

Though it shows the modal, but the second modal's button is not focusable.

Code:

package main

import (
	"time"

	"github.com/rivo/tview"
)

func main() {
	app := tview.NewApplication()

	pages := tview.NewPages()

	frmLogin := tview.NewForm().
		AddButton("Button A", func() {
			go func() {
				tv1 := tview.NewModal().SetText("Please wait...")
				pages.AddPage("modal1", tv1, true, true) // add modal page
				app.ForceDraw()
			}()
			// I WANT TO DO SOME TASK HERE...
			time.Sleep(2 * time.Second)
			pages.HidePage("modal1") //"hide Waiting modal"
			// TASK DONE...
			go func() {
				tv2 := tview.NewModal().
					SetText("Tank you for patient!").
					AddButtons([]string{"Okay"}).
					SetDoneFunc(func(buttonIndex int, buttonLabel string) {
						if buttonLabel == "Okay" {
							pages.SwitchToPage("formA")
						}
					})
				tv2.GetFocusable()
				pages.AddPage("modal2", tv2, true, true) // add modal page
				app.ForceDraw()
			}()
		}).
		AddButton("Quit", func() {
			app.Stop()
		})

	frmLogin.SetBorder(true).SetTitle("Demo Page").SetTitleAlign(tview.AlignCenter)
	pages.AddPage("formA", frmLogin, true, true)

	// run the app root tree
	if err := app.SetRoot(pages, true).SetFocus(pages).Run(); err != nil {
		panic(err)
	}
}

<!-- gh-comment-id:443667888 --> @thedevsaddam commented on GitHub (Dec 3, 2018): Though it shows the modal, but the second modal's button is not focusable. Code: ```go package main import ( "time" "github.com/rivo/tview" ) func main() { app := tview.NewApplication() pages := tview.NewPages() frmLogin := tview.NewForm(). AddButton("Button A", func() { go func() { tv1 := tview.NewModal().SetText("Please wait...") pages.AddPage("modal1", tv1, true, true) // add modal page app.ForceDraw() }() // I WANT TO DO SOME TASK HERE... time.Sleep(2 * time.Second) pages.HidePage("modal1") //"hide Waiting modal" // TASK DONE... go func() { tv2 := tview.NewModal(). SetText("Tank you for patient!"). AddButtons([]string{"Okay"}). SetDoneFunc(func(buttonIndex int, buttonLabel string) { if buttonLabel == "Okay" { pages.SwitchToPage("formA") } }) tv2.GetFocusable() pages.AddPage("modal2", tv2, true, true) // add modal page app.ForceDraw() }() }). AddButton("Quit", func() { app.Stop() }) frmLogin.SetBorder(true).SetTitle("Demo Page").SetTitleAlign(tview.AlignCenter) pages.AddPage("formA", frmLogin, true, true) // run the app root tree if err := app.SetRoot(pages, true).SetFocus(pages).Run(); err != nil { panic(err) } } ````
Author
Owner

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

This was indeed a bug which I just fixed.

A few notes about your code:

  • I'm not sure why you wrapped those calls in goroutines. It's not recommended that you do that as it can lead to race problems. Especially calling ForceDraw() is not recommended in a goroutine. I wrote that in the function comments.
  • tv2.GetFocusable() doesn't do anything in this context. It's an internal function anyway and not needed.
  • You don't need to call app.SetFocus(pages) as app.SetRoot(pages, true) already does that.

Here's an updated listing:

package main

import (
	"time"

	"github.com/rivo/tview"
)

func main() {
	app := tview.NewApplication()

	pages := tview.NewPages()

	frmLogin := tview.NewForm().
		AddButton("Button A", func() {
			tv1 := tview.NewModal().SetText("Please wait...")
			pages.AddPage("modal1", tv1, true, true) // add modal page
			app.ForceDraw()
			// I WANT TO DO SOME TASK HERE...
			time.Sleep(2 * time.Second)
			pages.HidePage("modal1") //"hide Waiting modal"
			// TASK DONE...
			tv2 := tview.NewModal().
				SetText("Tank you for your patience!").
				AddButtons([]string{"Okay"}).
				SetDoneFunc(func(buttonIndex int, buttonLabel string) {
					if buttonLabel == "Okay" {
						pages.SwitchToPage("formA")
					}
				})
			pages.AddPage("modal2", tv2, true, true) // add modal page
		}).
		AddButton("Quit", func() {
			app.Stop()
		})

	frmLogin.SetBorder(true).SetTitle("Demo Page").SetTitleAlign(tview.AlignCenter)
	pages.AddPage("formA", frmLogin, true, true)

	// run the app root tree
	if err := app.SetRoot(pages, true).Run(); err != nil {
		panic(err)
	}
}
<!-- gh-comment-id:443799521 --> @rivo commented on GitHub (Dec 3, 2018): This was indeed a bug which I just fixed. A few notes about your code: - I'm not sure why you wrapped those calls in goroutines. It's not recommended that you do that as it can lead to race problems. Especially calling `ForceDraw()` is not recommended in a goroutine. I wrote that in the function comments. - `tv2.GetFocusable()` doesn't do anything in this context. It's an internal function anyway and not needed. - You don't need to call `app.SetFocus(pages)` as `app.SetRoot(pages, true)` already does that. Here's an updated listing: ```go package main import ( "time" "github.com/rivo/tview" ) func main() { app := tview.NewApplication() pages := tview.NewPages() frmLogin := tview.NewForm(). AddButton("Button A", func() { tv1 := tview.NewModal().SetText("Please wait...") pages.AddPage("modal1", tv1, true, true) // add modal page app.ForceDraw() // I WANT TO DO SOME TASK HERE... time.Sleep(2 * time.Second) pages.HidePage("modal1") //"hide Waiting modal" // TASK DONE... tv2 := tview.NewModal(). SetText("Tank you for your patience!"). AddButtons([]string{"Okay"}). SetDoneFunc(func(buttonIndex int, buttonLabel string) { if buttonLabel == "Okay" { pages.SwitchToPage("formA") } }) pages.AddPage("modal2", tv2, true, true) // add modal page }). AddButton("Quit", func() { app.Stop() }) frmLogin.SetBorder(true).SetTitle("Demo Page").SetTitleAlign(tview.AlignCenter) pages.AddPage("formA", frmLogin, true, true) // run the app root tree if err := app.SetRoot(pages, true).Run(); err != nil { panic(err) } } ```
Author
Owner

@thedevsaddam commented on GitHub (Dec 4, 2018):

Thank you 👍 I really appreciate your reply with the solved code

<!-- gh-comment-id:443976459 --> @thedevsaddam commented on GitHub (Dec 4, 2018): Thank you 👍 I really appreciate your reply with the solved code
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#156
No description provided.