[GH-ISSUE #83] Feature Request: Progress Bar #63

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

Originally created by @SommerEngineering on GitHub (Mar 16, 2018).
Original GitHub issue: https://github.com/rivo/tview/issues/83

Dear rivo,

thanks for this great library. I'm working on a music playing app (VLC as backend) with tview: https://github.com/SommerEngineering/MusicPlayer Right now, it works only with macOS.

It would be great to have a simple progress bar: I could use it to show the current position of a song. Just need a SetProgress(percent int) function to set the position at the interval [0,100].

Is this doable?

Best regards
Thorsten

Originally created by @SommerEngineering on GitHub (Mar 16, 2018). Original GitHub issue: https://github.com/rivo/tview/issues/83 Dear rivo, thanks for this great library. I'm working on a music playing app (VLC as backend) with tview: https://github.com/SommerEngineering/MusicPlayer Right now, it works only with macOS. It would be great to have a simple progress bar: I could use it to show the current position of a song. Just need a `SetProgress(percent int)` function to set the position at the interval [0,100]. Is this doable? Best regards Thorsten
kerem closed this issue 2026-03-04 01:01:35 +03:00
Author
Owner

@rivo commented on GitHub (Mar 18, 2018):

Hi Thorsten, glad that you like tview. At the moment, there is no progress bar. This is somewhat related to #11 where people asked for charts. I'm planning to add chart functionality to tview at some point the future but probably not soon enough for you if you need it now.

Until then, I suggest that you build your own progress bar. You may be able to use the TextView element for it, by writing U+25A0 characters to it. Or, if you need to get more advanced, you can use SetDrawFunc() to write characters to a Box. I believe this should be help you implement a progress bar.

I'm currently working on a Wiki page with examples how to implement your own widget: https://github.com/rivo/tview/wiki/Primitives It's not complete yet, though. I'll try to finish it in the next few days.

<!-- gh-comment-id:374017245 --> @rivo commented on GitHub (Mar 18, 2018): Hi Thorsten, glad that you like `tview`. At the moment, there is no progress bar. This is somewhat related to #11 where people asked for charts. I'm planning to add chart functionality to `tview` at some point the future but probably not soon enough for you if you need it now. Until then, I suggest that you build your own progress bar. You may be able to use the `TextView` element for it, by writing `U+25A0` characters to it. Or, if you need to get more advanced, you can use [`SetDrawFunc()`](https://godoc.org/github.com/rivo/tview#Box.SetDrawFunc) to write characters to a `Box`. I believe this should be help you implement a progress bar. I'm currently working on a Wiki page with examples how to implement your own widget: https://github.com/rivo/tview/wiki/Primitives It's not complete yet, though. I'll try to finish it in the next few days.
Author
Owner

@muesli commented on GitHub (Mar 18, 2018):

Shouldn't we keep the issue open since it's still a valid ticket worth tracking?

<!-- gh-comment-id:374028512 --> @muesli commented on GitHub (Mar 18, 2018): Shouldn't we keep the issue open since it's still a valid ticket worth tracking?
Author
Owner

@rivo commented on GitHub (Mar 18, 2018):

If there's ever going to be a progress bar (which I'm really not sure at this point), it is going to be part of the charts. And the charts are really far out, v2.0 or something. I don't believe @SommerEngineering will wait that long, especially when he has other options to achieve his goal right now.

<!-- gh-comment-id:374038843 --> @rivo commented on GitHub (Mar 18, 2018): If there's ever going to be a progress bar (which I'm really not sure at this point), it is going to be part of the charts. And the charts are really far out, v2.0 or something. I don't believe @SommerEngineering will wait that long, especially when he has other options to achieve his goal right now.
Author
Owner

@majimboo commented on GitHub (Apr 18, 2019):

Still waiting for this or a sample code for the implementation with a box would be acceptable too.

<!-- gh-comment-id:484324174 --> @majimboo commented on GitHub (Apr 18, 2019): Still waiting for this or a sample code for the implementation with a box would be acceptable too.
Author
Owner

@rivo commented on GitHub (Apr 18, 2019):

Apologies. I'm traveling at the moment with very little internet access. Will get back to the open issues when I get back.

Sent from my iPhone

Am 18.04.2019 um 04:47 schrieb Majid Arif Siddiqui notifications@github.com:

Still waiting for this or a sample code for the implementation with a box would be acceptable too.


You are receiving this because you modified the open/close state.
Reply to this email directly, view it on GitHub, or mute the thread.

<!-- gh-comment-id:484369154 --> @rivo commented on GitHub (Apr 18, 2019): Apologies. I'm traveling at the moment with very little internet access. Will get back to the open issues when I get back. Sent from my iPhone > Am 18.04.2019 um 04:47 schrieb Majid Arif Siddiqui <notifications@github.com>: > > Still waiting for this or a sample code for the implementation with a box would be acceptable too. > > — > You are receiving this because you modified the open/close state. > Reply to this email directly, view it on GitHub, or mute the thread.
Author
Owner

@lancerushing commented on GitHub (Jan 16, 2020):

Using rivo's suggestion to use U+25A0 characters, I made this example:

package main

import (
	"fmt"
	"strings"
	"time"

	"github.com/rivo/tview"
)

func main() {
	app := tview.NewApplication()
	textView := tview.NewTextView().
		SetChangedFunc(func() {
			app.Draw()
		})

	messages := make(chan struct{}, 50)

	go func() { // Simple channel status gauge (progress bar)
		ccap := cap(messages)
		barSize := 100
		for {
			clen := len(messages)
			barComplete := barSize * clen / ccap
			textView.Clear()
			_, _ = fmt.Fprintf(textView, "channel status:  %s%s %d/%d",
				strings.Repeat("■", barComplete),
				strings.Repeat("□", barSize-barComplete),
				clen, ccap)

			time.Sleep(100 * time.Millisecond)
		}
	}()

	go func() { // Example: add work onto the channel
		for {
			messages <- struct{}{}
			time.Sleep(30 * time.Millisecond)
		}
	}()

	go func() { // Example: remove work from channel
		time.Sleep(time.Second)
		for range messages {
			if len(messages) < 10 { // let a few messages queue up for this example
				time.Sleep(1000 * time.Millisecond)
			}

			time.Sleep(20 * time.Millisecond) //
		}
	}()

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

<!-- gh-comment-id:575280082 --> @lancerushing commented on GitHub (Jan 16, 2020): Using rivo's suggestion to use U+25A0 characters, I made this example: ```golang package main import ( "fmt" "strings" "time" "github.com/rivo/tview" ) func main() { app := tview.NewApplication() textView := tview.NewTextView(). SetChangedFunc(func() { app.Draw() }) messages := make(chan struct{}, 50) go func() { // Simple channel status gauge (progress bar) ccap := cap(messages) barSize := 100 for { clen := len(messages) barComplete := barSize * clen / ccap textView.Clear() _, _ = fmt.Fprintf(textView, "channel status: %s%s %d/%d", strings.Repeat("■", barComplete), strings.Repeat("□", barSize-barComplete), clen, ccap) time.Sleep(100 * time.Millisecond) } }() go func() { // Example: add work onto the channel for { messages <- struct{}{} time.Sleep(30 * time.Millisecond) } }() go func() { // Example: remove work from channel time.Sleep(time.Second) for range messages { if len(messages) < 10 { // let a few messages queue up for this example time.Sleep(1000 * time.Millisecond) } time.Sleep(20 * time.Millisecond) // } }() if err := app.SetRoot(textView, true).SetFocus(textView).Run(); err != nil { panic(err) } } ```
Author
Owner

@raziman18 commented on GitHub (Jun 21, 2020):

A slightly more simple example

package main

import (
	"fmt"
	"strings"
	"time"

	"github.com/gdamore/tcell"
	"github.com/rivo/tview"
)

type Progress struct {
	textView *tview.TextView
	full     int
	limit    int
	progress chan int
}

// full is the maximum amount of value can be sent to channel
// limit is the progress bar size
func (p *Progress) Init(full int, limit int) chan int {
	p.progress = make(chan int)
	p.full = full
	p.limit = limit


	go func() { // Simple channel status gauge (progress bar)
		progress := 0
		for {
			progress += <-p.progress

			if progress > full {
				break
			}

			x := progress * limit / full
			p.textView.Clear()
			_, _ = fmt.Fprintf(p.textView, "channel status:  %s%s %d/%d",
				strings.Repeat("■", x),
				strings.Repeat("□", limit-x),
				progress, full)

		}
	}()

	return p.progress
}

func main() {
	app := tview.NewApplication()
	textView := tview.NewTextView().
		SetChangedFunc(func() {
			app.Draw()
		})

	textView.SetBorder(true)
	textView.SetBackgroundColor(tcell.ColorDefault)

	progress := Progress{textView: textView}
	progChan := progress.Init(360, 20)



	go func() { // update progress bar

		i := 0

		for {
			i++
			progChan <- 1

			if i > progress.full {
				close(progChan)
				break
			}

			time.Sleep(100 * time.Millisecond)
		}
	}()

	if err := app.SetRoot(textView, true).SetFocus(textView).Run(); err != nil {
		panic(err)
	}
}
<!-- gh-comment-id:647100795 --> @raziman18 commented on GitHub (Jun 21, 2020): A slightly more simple example ```golang package main import ( "fmt" "strings" "time" "github.com/gdamore/tcell" "github.com/rivo/tview" ) type Progress struct { textView *tview.TextView full int limit int progress chan int } // full is the maximum amount of value can be sent to channel // limit is the progress bar size func (p *Progress) Init(full int, limit int) chan int { p.progress = make(chan int) p.full = full p.limit = limit go func() { // Simple channel status gauge (progress bar) progress := 0 for { progress += <-p.progress if progress > full { break } x := progress * limit / full p.textView.Clear() _, _ = fmt.Fprintf(p.textView, "channel status: %s%s %d/%d", strings.Repeat("■", x), strings.Repeat("□", limit-x), progress, full) } }() return p.progress } func main() { app := tview.NewApplication() textView := tview.NewTextView(). SetChangedFunc(func() { app.Draw() }) textView.SetBorder(true) textView.SetBackgroundColor(tcell.ColorDefault) progress := Progress{textView: textView} progChan := progress.Init(360, 20) go func() { // update progress bar i := 0 for { i++ progChan <- 1 if i > progress.full { close(progChan) break } time.Sleep(100 * time.Millisecond) } }() if err := app.SetRoot(textView, true).SetFocus(textView).Run(); err != nil { panic(err) } } ```
Author
Owner

@tslocum commented on GitHub (Oct 15, 2020):

A ProgressBar widget is available in cview, a fork of tview. A PR to include the widget in tview was submitted as #388.

Demo: ssh cview.rocketnine.space -p 20000

<!-- gh-comment-id:708874885 --> @tslocum commented on GitHub (Oct 15, 2020): A [ProgressBar](https://gitlab.com/tslocum/cview/-/blob/master/progressbar.go) widget is available in [cview](https://gitlab.com/tslocum/cview), a fork of tview. A PR to include the widget in tview was submitted as #388. Demo: `ssh cview.rocketnine.space -p 20000`
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#63
No description provided.