微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

我如何使用 tkinter/ttk 制作多个单独的进度条,其中包含百分比?

如何解决我如何使用 tkinter/ttk 制作多个单独的进度条,其中包含百分比?

我一直在尝试为 DnD 会话的游戏大师设计一个小帮助工具,用于记录玩家在统计数据和技能方面的升级进度。我希望这些统计数据与进度条一起显示,其中包含一个百分比,在它们下方,我完全能够使用没有任何百分比的常规进度条来做到这一点:

progress bars without percentage

但是一旦我尝试按照我在此处找到的示例来获取内部带有百分比的进度条,它们就会以某种方式相互连接,将百分比加在一起并在每个进度条中显示总数

progress bars with percentage

控制台输出如下:

"Smith's tools | Progress: 1253/2000
62.64999999999999
Dragonchess set | Progress: 24/2000
1.2"

当加在一起时,它加起来为 63.84999,这导致上图中四舍五入的总百分比为 63.85。

这些是在我为保存的每个字符调用函数中创建的,最初我复制了来自 this post代码,这导致所有进度条汇总在一起,而使用当前代码显示每个字符单独的总百分比,然后将其与下一个字符的百分比相加,所有进度条都会填充到最高百分比。

highest percentage filled

这是我第一次在这里发帖,所以如果您需要更多代码或详细信息,请告诉我。产生这些奇怪的填充结果的函数如下:

def buildbasicobjectinfo(elems,charfield,charname):
pbnum = 0
for elem in elems:
    try:

        style.layout('TProgressbar.'+str(charname)+'.'+str(pbnum),[('Progressbar.trough',{'children': [('Horizontal.Progressbar.pbar',{'side': 'left','sticky': 'ns'})],'sticky': 'nswe'}),('Progressbar.label',{'sticky': ''})])

        t = elem.childNodes[0].firstChild.data+" | Progress: "+elem.childNodes[2].firstChild.data+"/"+elem.childNodes[1].firstChild.data
        print(t)
        progress = tk.Label(charfield,text=t)
        progress.pack(anchor="w")
        pbar = ttk.Progressbar(charfield,style='TProgressbar.'+str(charname)+'.'+str(pbnum),variable=variable)
        print("variable="+str(variable))
        
        percentage = float(float(elem.childNodes[2].firstChild.data)/float(elem.childNodes[1].firstChild.data)*100)
        print(percentage)
        pbar.step(percentage)
        pbar.pack(anchor="w")
        
        style.configure('TProgressbar.'+str(charname)+'.'+str(pbnum),text='{:g} %'.format(variable.get()))
        pbnum = pbnum+1
    except AttributeError:
        print(elem,elem.childNodes[0])

这里是相同功能代码,没有样式部分就可以正常工作:

working progress bars image

def buildbasicobjectinfo(elems,charname):
    for elem in elems:
        try:
            percentage = round(float(float(elem.childNodes[2].firstChild.data)/float(elem.childNodes[1].firstChild.data)*100),2) #calculate the percentage
            print(percentage) #print percentage in console

            t = elem.childNodes[0].firstChild.data+" | Progress: "+elem.childNodes[2].firstChild.data+"/"+elem.childNodes[1].firstChild.data+" | Percentage: "+str(percentage)+"%" #format necessary data
            print(t) #print data in console

            #create label for data in text format
            progress = tk.Label(charfield,text=t)
            progress.pack(anchor="w")

            #create progress bar
            pbar = ttk.Progressbar(charfield,orient="horizontal",mode="determinate",length=300)
            pbar.step(percentage) #fill progress bar with compelted percentage
            pbar.pack(anchor="w")
        except AttributeError:
            print(elem,elem.childNodes[0])

对于那些对演示问题的小程序感兴趣的人应该这样做,在左侧它将显示 2 个进度条,以正常方式并正确显示,在右侧它将显示 2 个以相同方式创建的进度条方式,但通过添加样式将百分比可视化添加到进度条本身以及它们如何由于某种原因相互添加,在每个条形上方它将显示它们应该处于的百分比:

import tkinter as tk
import tkinter.ttk as ttk

#function to divide the centered frame evenly,replicates distribution of character placement
def sidebysidedisplay(data,frame):
    npbframe = tk.LabelFrame(frame,text="normal bars",bd=0,font=(0,12,'bold'))
    npbframe.grid(row=1,column=0,sticky="nesw",padx=(0,20))

    spbframe = tk.LabelFrame(frame,text="styled bars",'bold'))
    spbframe.grid(row=1,column=1,padx=(20,0))

    normalprogressbar(data,npbframe)
    styledprogressbar(data,spbframe)


def normalprogressbar(items,frame):
    print("normal progress bars")
    for item in items:
        percentage = round(float(float(item[0])/float(item[1])*100),2)
        print("Item: "+str(item)+" | Percentage: "+str(percentage))
        progress = tk.Label(frame,text=percentage)
        progress.pack(anchor="w")

        pbar = ttk.Progressbar(frame,length=400)
        pbar.step(percentage)
        pbar.pack(anchor="w")

def styledprogressbar(items,frame):
    print("Styled progress bars")
    for item in items:
        percentage = round(float(float(item[0])/float(item[1])*100),2)
        print("Item: "+str(item)+" | Percentage: "+str(percentage))
        style.layout('text.Horizontal.TProgressbar.'+str(item),[('Horizontal.Progressbar.trough',('Horizontal.Progressbar.label',{'sticky': ''})])

        progress = tk.Label(frame,style='text.Horizontal.TProgressbar.'+str(item),variable=variable,length=400)
        pbar.step(percentage)
        pbar.pack(anchor="w")
        style.configure('text.Horizontal.TProgressbar.'+str(item),text='{:g} %'.format(variable.get()))  # update label

#====================================================================================================#

root = tk.Tk()
root.state("zoomed")
data = ((1253,2000),(24,2000)) #mock data to recreate data read from xml file

style = ttk.Style(root)
variable = tk.DoubleVar(root)

#create centered frame to display data in the center of the screen
centerframe = tk.LabelFrame(root,bd=0)
centerframe.place(relx=.5,rely=.5,anchor="c")


sidebysidedisplay(data,centerframe)

root.mainloop()

解决方法

运行代码后,我发现问题使 variable = tk.DoubleVar(root)

您将一个 variable 用于两个 Progressbars 并且 pbar.step(percentage) 将值添加到 variable,因此最终您得到总和 63.83%

这也造成了其他问题。如果您更改 variable 中的值,则它会更改 Progressbar 中的长度,并且您会在两个小部件中看到相同的长度。

您应该删除 variable

pbar = ttk.Progressbar(frame,length=400,style='text.Horizontal.TProgressbar.'+str(item))

使用 percentage 显示文本

style.configure('text.Horizontal.TProgressbar.'+str(item),text='{:g} %'.format(percentage) ) # update label

或者您必须为两个 variables 创建两个 Progressbars


编辑:

您也可以创建自己的小部件 - 您可以使用 Frame 通过 LabelProgressbarvariable 创建小部件。


使用 variable 的工作代码

import tkinter as tk
import tkinter.ttk as ttk

#function to divide the centered frame evenly,replicates distribution of character placement
def sidebysidedisplay(data,frame):
    npbframe = tk.LabelFrame(frame,text="normal bars",bd=0,font=(0,12,'bold'))
    npbframe.grid(row=1,column=0,sticky="nesw",padx=(0,20))

    spbframe = tk.LabelFrame(frame,text="styled bars",'bold'))
    spbframe.grid(row=1,column=1,padx=(20,0))

    normalprogressbar(data,npbframe)
    styledprogressbar(data,spbframe)


def normalprogressbar(items,frame):
    print("Normal progress bars")
    for item in items:
        percentage = round(float(float(item[0])/float(item[1])*100),2)
        print("Item: "+str(item)+" | Percentage: "+str(percentage))
        progress = tk.Label(frame,text=percentage)
        progress.pack(anchor="w")

        pbar = ttk.Progressbar(frame,orient="horizontal",mode="determinate",length=400)
        pbar.step(percentage)
        pbar.pack(anchor="w")

def styledprogressbar(items,frame):
    print("Styled progress bars")
    for item in items:
        percentage = round(float(float(item[0])/float(item[1])*100),2)
        print("Item: "+str(item)+" | Percentage: "+str(percentage))
        style.layout('text.Horizontal.TProgressbar.'+str(item),[('Horizontal.Progressbar.trough',{'children': [('Horizontal.Progressbar.pbar',{'side': 'left','sticky': 'ns'})],'sticky': 'nswe'}),('Horizontal.Progressbar.label',{'sticky': ''})])

        progress = tk.Label(frame,text=percentage)
        progress.pack(anchor="w")

        #pbar = ttk.Progressbar(frame,style='text.Horizontal.TProgressbar.'+str(item),variable=variable,length=400)
        pbar = ttk.Progressbar(frame,length=400)
        pbar.step(percentage)
        pbar.pack(anchor="w")
        
        #style.configure('text.Horizontal.TProgressbar.'+str(item),text='{:g} %'.format(variable.get()))  # update label
        style.configure('text.Horizontal.TProgressbar.'+str(item),text='{:g} %'.format(percentage))  # update label

#====================================================================================================#

root = tk.Tk()
#root.state("zoomed")
data = ((1253,2000),(24,2000)) #mock data to recreate data read from xml file

style = ttk.Style(root)
variable = tk.DoubleVar(root)

#create centered frame to display data in the center of the screen
centerframe = tk.LabelFrame(root,bd=0)
centerframe.place(relx=.5,rely=.5,anchor="c")


sidebysidedisplay(data,centerframe)

root.mainloop()

编辑:

带有自己的小部件的版本

import tkinter as tk
import tkinter.ttk as ttk

class MyWidget(tk.Frame):
    
    def __init__(self,parent,item,*args,**kwargs):
        super().__init__(parent,**kwargs)

        self.item = item
        
        self.percentage = round(100*item[0]/item[1],2)

        print("[MyWidget] Item: {} | Percentage: {}".format(self.item,self.percentage))
        
        style_name = 'text.Horizontal.TProgressbar.'+str(item)

        style.layout(style_name,{'sticky': ''})])

            
        self.label = tk.Label(self,text=self.percentage)
        self.label.pack(anchor="w")

        self.pbar = ttk.Progressbar(self,style=style_name,length=400)
        self.pbar.step(self.percentage)
        self.pbar.pack(anchor="w")
        
        style.configure(style_name,text='{:g} %'.format(self.percentage))
            
#function to divide the centered frame evenly,spbframe)

    widgetsframe = tk.LabelFrame(frame,text="widgets",'bold'))
    widgetsframe.grid(row=1,column=2,0))

    for item in data:
        w = MyWidget(widgetsframe,item)
        w.pack()

def normalprogressbar(items,frame):
    print("Styled progress bars")
    for item in items:
        
        percentage = round(item[0]/item[1]*100,2)
        print("Item: {} | Percentage: {}".format(item,percentage))
        
        style_name = 'text.Horizontal.TProgressbar.'+str(item)
        
        style.layout(style_name,length=400)
        pbar.step(percentage)
        pbar.pack(anchor="w")
        
        style.configure(style_name,text='{:g} %'.format(percentage))

#====================================================================================================#

root = tk.Tk()
#root.state("zoomed")
data = ((1253,anchor="c")

sidebysidedisplay(data,centerframe)

root.mainloop()

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。