我第一次看到这个库,但在研究了一些代码后,我发现如何添加新的和定制我们想要的栏.我已经做了一些修改的例子,您在您的 comments 中提供了链接,以演示添加和定制的栏.
package main
import (
"fmt"
"io"
"math/rand"
"time"
"github.com/vbauerster/mpb/v8"
"github.com/vbauerster/mpb/v8/decor"
)
func main() {
p := mpb.New()
var piece, piece2 int64
var way, way2 int64
file := func(_ decor.Statistics) string {
return "file.extension "
}
file2 := func(_ decor.Statistics) string {
return "file2.extension "
}
part := func(s decor.Statistics) string {
s.Current = piece
s.Total = 5
return fmt.Sprintf(" Part %d/%d", s.Current, s.Total)
}
part2 := func(s decor.Statistics) string {
s.Current = piece2
s.Total = 10
return fmt.Sprintf(" Part %d/%d", s.Current, s.Total)
}
pass := func(s decor.Statistics) string {
s.Current = way
s.Total = 2
return fmt.Sprintf(" Pass %d/%d", s.Current, s.Total)
}
pass2 := func(s decor.Statistics) string {
s.Current = way2
s.Total = 4
return fmt.Sprintf(" Pass %d/%d", s.Current, s.Total)
}
var total = 100
bar := p.New(int64(total),
mpb.NopStyle(), // make main bar style nop, so there are just decorators
mpb.BarExtender(extended(mpb.BarStyle().Build()), false), // extend wtih normal bar on the next line
mpb.PrependDecorators(
decor.Any(file),
decor.Name("Percentage: "),
decor.NewPercentage("%d"),
decor.Any(part),
decor.Any(pass),
),
)
bar2 := p.New(int64(total+100),
mpb.NopStyle(),
mpb.BarExtender(extended(mpb.BarStyle().Build()), false),
mpb.PrependDecorators(
decor.Any(file2),
decor.Name("Percentage: "),
decor.NewPercentage("%d"),
decor.Any(part2),
decor.Any(pass2),
),
)
// simulating some work
max := 100 * time.Millisecond
for i := 0; i < total+100; i++ {
switch {
case i == 20 || i == 40 || i == 60 ||
i == 80 || i == 100 || i == 120 ||
i == 140 || i == 160 || i == 180:
piece2++
if i == 100 {
way2++
piece = 5
way = 2
} else if i < 100 {
piece++
}
case i == 50 || i == 150:
if i < 100 {
way++
}
way2++
}
time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10)
if i < 100 {
bar.Increment()
}
bar2.Increment()
}
way2 = 4
piece2 = 10
// wait for our bar to complete and flush
p.Wait()
}
func extended(base mpb.BarFiller) mpb.BarFiller {
return mpb.BarFillerFunc(func(w io.Writer, st decor.Statistics) error {
err := base.Fill(w, st)
if err != nil {
return err
}
_, err = io.WriteString(w, "\n")
return err
})
}
假设您已经知道如何创建自定义decorator .
要创建新条形图,可以使用p.New()
方法:
bar := p.New(int64(total),
mpb.NopStyle(), // make main bar style nop, so there are just decorators
mpb.BarExtender(extended(mpb.BarStyle().Build()), false), // extend wtih normal bar on the next line
mpb.PrependDecorators(
decor.Any(file),
decor.Name("Percentage: "),
decor.NewPercentage("%d"),
decor.Any(part),
decor.Any(pass),
),
)
In this example to demonstrative the making new bars I have used 101 method but there are more ways to make a new bar. The difference is mostly how the bars will look. You can find them by looking methods that returns 102 instance in method list of the103 struct in the 100.
I have only made two bars for example, but you can make more than two.个
p.New()
的第一个参数是指定条形图的值.
在我的示例中,两个条形图的值分别为p.New()
和200.
只要把你的装修工调到mpb.PrependDecorators
或mpb.AppendDecorators
就行了.
mpb.PrependDecorators(
decor.Any(file),
decor.Name("Percentage: "),
decor.NewPercentage("%d"),
decor.Any(part),
decor.Any(pass),
),
You can use the same decorators for every bar but I recommend making new one for every bar to avoid possibility of conflicts.个
The external decorators of the two bars in my example are respectively:
decor.Any(file)
, decor.Any(part)
and decor.Any(pass)
for the first bar.
decor.Any(file2)
, decor.Any(part2)
and decor.Any(pass2)
for the second bar.
The internal decorators for both are same:
decor.Name("Percentage: ")
, decor.NewPercentage("%d")
.
I will explain why I used the terms internal and external for decors together with explanation of the loop that is responsible for increase the status of the decors.个
这将分别显示文件名、百分比、部件和通过:
file.extension Percentage: 100% Part 5/5 Pass 2/2
[==============================================================================]
让我们来讨论一下负责增加两个wine 吧所有装饰的状态的循环.
for i := 0; i < total+100; i++ {
switch {
case i == 20 || i == 40 || i == 60 ||
i == 80 || i == 100 || i == 120 ||
i == 140 || i == 160 || i == 180:
piece2++
if i == 100 {
way2++
piece = 5
way = 2
} else if i < 100 {
piece++
}
case i == 50 || i == 150:
if i < 100 {
way++
}
way2++
}
time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10)
if i < 100 {
bar.Increment()
}
bar2.Increment()
}
I aimed the values of the both bars to same step which is 20 to increase the Part
decoration by 1 which will result in 5 increases for the 100 and 10 increases for the 200. When it comes to Pass
decoration I aimed the step 50 which will result in 2 increases for the 100, 4 increases for the 200. When the loop variable encounters any of the step for Part
decoration or step of Pass
the related decoration increase by 1. Actually these decors are not related with Percentage
decor. Percentage
decor something special to bar's value directly. In this example it will only increase by 1 with these method calls:
bar.Increment()
, bar2.Increment()
.
Because the first bar's value is 100 the loop will increase its percentage in every 1 iteration, but second bar's value is 200, percentage of it increases every 2 iterations.
For first bar, loop var = 1 and 2: Percentage: 1% [>], Percentage: 2% [=>]
For second bar, loop var = 2 and 4: Percentage: 1% [>], Percentage: 2% [=>]
一百零二
整个代码的输出为:
file.extension Percentage: 9% Part 0/5 Pass 0/2
[======>-----------------------------------------------------------------------]
file2.extension Percentage: 4% Part 0/10 Pass 0/4
[===>--------------------------------------------------------------------------]
file.extension Percentage: 49% Part 2/5 Pass 0/2
[=====================================>----------------------------------------]
file2.extension Percentage: 24% Part 2/10 Pass 0/4
[==================>-----------------------------------------------------------]
file.extension Percentage: 100% Part 5/5 Pass 2/2
[==============================================================================]
file2.extension Percentage: 74% Part 7/10 Pass 2/4
[=========================================================>--------------------]
file.extension Percentage: 100% Part 5/5 Pass 2/2
[==============================================================================]
file2.extension Percentage: 100% Part 10/10 Pass 4/4
[==============================================================================]
Additional Example个
package main
import (
"bufio"
"fmt"
"io"
"log"
"os"
"github.com/vbauerster/mpb/v8"
"github.com/vbauerster/mpb/v8/decor"
)
func main() {
p := mpb.New()
f, err := os.Create("file.extension")
if err != nil {
log.Fatal(err)
}
// change file size to 10MB
if err := f.Truncate(1e7); err != nil {
log.Fatal(err)
}
// delete the dumb file when our demonstrative finish
defer os.Remove("file.extension")
defer f.Close()
status, err := f.Stat()
if err != nil {
log.Fatal(err)
}
sizeOfFile := status.Size()
var piece, way int64
var currentMb int64
file := func(s decor.Statistics) string {
return status.Name() + " "
}
part := func(s decor.Statistics) string {
s.Current = piece
s.Total = 5
return fmt.Sprintf(" Part %d/%d", s.Current, s.Total)
}
pass := func(s decor.Statistics) string {
s.Current = way
s.Total = 2
return fmt.Sprintf(" Pass %d/%d", s.Current, s.Total)
}
mbInfo := func(s decor.Statistics) string {
s.Current = currentMb
s.Total = 10
return fmt.Sprintf(" Size %d/%dMB", s.Current, s.Total)
}
bar := p.New(int64(sizeOfFile),
mpb.NopStyle(), // make main bar style nop, so there are just decorators
mpb.BarExtender(extended(mpb.BarStyle().Build()), false), // extend wtih normal bar on the next line
mpb.PrependDecorators(
decor.Any(file),
decor.Name("Percentage: "),
decor.NewPercentage("%d"),
decor.Any(part),
decor.Any(pass),
decor.Any(mbInfo),
),
)
r := bufio.NewReader(f)
var sendReadBytes = make(chan int)
var done = make(chan struct{})
var n int
var reach int
valueOfPiece := sizeOfFile / 5
go func() {
for {
buf := make([]byte, 4)
n, err = r.Read(buf)
sendReadBytes <- n
reach += n
if n == 0 {
if err != nil {
fmt.Println(err)
break
}
if err == io.EOF {
break
}
return
}
<-done
}
}()
for {
if reach == int(sizeOfFile) {
break
}
switch int64(reach) {
case valueOfPiece:
piece++
case valueOfPiece * 2:
piece++
case sizeOfFile / 2:
way++
case valueOfPiece * 3:
piece++
case valueOfPiece * 4:
piece++
}
// increase the progress every time 4 bytes
bar.IncrBy(<-sendReadBytes)
// convert current progress value to MB
currentMb = bar.Current() / 1000000
done <- struct{}{}
}
piece++
way++
p.Wait()
}
func extended(base mpb.BarFiller) mpb.BarFiller {
return mpb.BarFillerFunc(func(w io.Writer, st decor.Statistics) error {
err := base.Fill(w, st)
if err != nil {
return err
}
_, err = io.WriteString(w, "\n")
return err
})
}
This is just for how to change the bar's progress to something different. Also show how these external decors are useful.
To make things shorter I will briefly explain what this doing. This example makes a dumb file its size 10MB. Makes a bar its value is file's size. Read 4 bytes from the file then send that value to bar's increment value, to demonstrative how to progress through reading a file. And external decors are used to record how many parts and how many MB passed successfully.
Output:
file.extension Percentage: 55% Part 2/5 Pass 1/2 Size 5/10MB [==========================================>-----------------------------------]
This example would possible without making a concurrent function. But I wanted the divide the progress area from the file read area to make the code simpler that is why I used it. I didn't made the second example multi bar to make the code sorter.