【问题标题】:ttk.Progressbar using python 3.1.4 tkinter 8.5 won't startttk.Progressbar 使用 python 3.1.4 tkinter 8.5 不会启动
【发布时间】:2011-09-05 21:45:47
【问题描述】:

我已经编写了一些 python 3.1 代码(真的很简单,因为我没有程序员),我正在尝试使用 tkinter 8.5 和 python 3.1.4 将 GUI 放入其中。我遇到的问题是进度条无法启动。以下是部分代码:

def transformation(Xn,Yn,Zn,const):

     infile = filedialog.askopenfile('r')
     outfile = filedialog.asksaveasfile('w')      

     pbar.start()

     for line in infile.readlines():                                 
              inlist = line.split(" ")
              inlist = [float(i) for i in inlist] 

              l = (Xn+Yn+Zn)/const**2

              Xm = inlist[0] + Xn*l
              Ym = inlist[1] + Yn*l
              Zm = inlist[2] + Zn*l

              outlist=[0,0,0]  
              outlist[0] = inlist[0] + 2*(Xm-inlist[0])
              outlist[1] = inlist[1] + 2*(Ym-inlist[1])
              outlist[2] = inlist[2] + 2*(Zm-inlist[2])

              outdata = str('%.4f' %outlist[0])+" "+str('%.4f' %outlist[1])+" "+str('%.4f' %outlist[2])+"\n"

              outfile.writelines(outdata)


     infile.close()    
     outfile.close() 

     pbar.stop()

函数正在被一个按钮调用。我提供了程序工作所需的所有文件。计算成功完成,但条形图从未开始。有什么想法吗?

谢谢, 亚历克斯

【问题讨论】:

    标签: progress-bar tkinter


    【解决方案1】:

    栏开始了,您只是没有看到它,因为您没有给 UI 重绘的机会。到屏幕重绘时,您已经停止了进度条。重绘是为了响应重绘事件而发生的,这些事件由事件循环处理。当您的代码处于读取数据的循环中时,您正在阻止事件循环运行。

    您将需要 a) 使用线程或单独的进程来执行 IO,以免使事件循环饿死,b) 您需要将处理分成可以在每次迭代期间完成的小块事件循环,或 c) 在循环的每次迭代期间调用 update_idletasks;此方法处理包括屏幕刷新在内的“空闲”事件。

    Google 中的“tkinter 长期运行计算”提供了很多建议。

    【讨论】:

    • 能否请教我如何在上面的代码中使用 update_idletasks 命令?不幸的是,我不是编程专家。我只是想为我的项目制作一个像样的应用程序。谢谢!
    • @AlexTh:首先,尝试在循环结束时调用root.update_idletasks()(将root 替换为您对Tk 实例的引用)。不要在循环之后执行,而是在内部执行,以便在每次迭代时调用它。
    • root.update_idletasks 不起作用。相反,root.update() 在 outfile.writelines(outdata) 行之后的循环内工作正常。
    • root.update 对于实际应用来说是非常危险的。除了爱好应用程序之外,不要养成为任何事情调用它的习惯。它所做的是创建一个 new 事件循环。如果你很幸运,它是无害的,但如果你在处理第一次按钮点击时再次点击同一个按钮,它真的会适得其反。
    • 真说。但是,既然 root.update_idletasks 不起作用,我该怎么办?
    【解决方案2】:

    您需要使用 step 或 set 更新进度条,或者更改附加到进度条的 IntVar 变量的值。

    这可能会有所帮助。本例启动一个主窗口,可以打开多个进度条 通过自动方法在循环中递增。在这个小示例中,您的截止日期循环服务于自动方法的目的。

    将 tkinter 导入为 tk 从 tkinter 导入 ttk 进口时间

    类主窗口:

    def __init__(self):
        self.pbars = []
    
        self.parent = tk.Tk()
        self.parent.title('multiprocessing progess bar')
    
        frame = ttk.Labelframe(self.parent)
        frame.pack(pady=10, padx=10)
    
        btn = tk.Button(frame, text="Cancel")
        btn.bind("<Button-1>", self.cancel)
        btn.grid(row=0, column=1, pady=10)
    
        btn = tk.Button(frame, text="progress_bar")
        btn.bind("<Button-1>", self.pbar)
        btn.grid(row=0, column=2, pady=10)
    
        btn = tk.Button(frame, text="increment")
        btn.bind("<Button-1>", self.increment)
        btn.grid(row=0, column=3, pady=10)
    
        self.parent.mainloop()
    
    
    def pbar(self, event):
    
        count= len(self.pbars)
        name="producer %d" % count
    
        print (count*10)
        self.pbars.append(pbar_dialog(self.parent, title=name, count=count*10))
        pbar.automatic()
    
    def cancel(self, event):
       self.parent.destroy()
    
    def increment(self, event):
       for pbar in self.pbars:
           pbar.step(10)
    

    类 pbar_dialog:

    toplevel=None
    pbar_count = 0
    
    def __init__(self, parent, count=0, title=None):
        self.pbar_value = count
        self.title=title
    
        pbar_dialog.pbar_count += 1
    
        if not pbar_dialog.toplevel:
            pbar_dialog.toplevel= tk.Toplevel(parent)
    
        self.frame = ttk.Labelframe(pbar_dialog.toplevel, text=title)
        #self.frame.pack()
        self.pbar = ttk.Progressbar(self.frame, length=300, variable=self.pbar_value)
        self.pbar.grid(row=0, column=1, columnspan=2, padx=5, pady=5)
    
        btn = tk.Button(self.frame, text="Cancel")
        btn.bind("<Button-1>", self.cancel)
        btn.grid(row=0, column=3, pady=10)
        self.frame.pack()
    
        self.pbar.step(count)
    
    def set(self,value):
        self.pbar_value=value
    
    def step(self,increment=1):
        self.pbar.step(increment)
    
    def cancel(self, event):
       self.destroy()
    
    def destroy(self):
        self.frame.destroy()
        pbar_dialog.pbar_count -= 1
        if pbar_dialog.pbar_count == 0:
            pbar_dialog.toplevel.destroy()
    
    def automatic(self): 
        for i in range(self.pbar_value, 100):
            time.sleep(1)
            #self.step()
            print(self.title, i)
            self.set(i)
    

    如果 name == 'ma​​in':

    main_window()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-09-13
      • 1970-01-01
      • 2013-05-04
      • 2021-08-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多