tkinter 中的进度条不起作用 [英] Progress bar in tkinter not working

查看:97
本文介绍了tkinter 中的进度条不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个小应用程序来复制一些文件.我做了几乎所有我想要的东西,但只有三件事:

I am writing a small app to copy some files. I have made almost everything that I wanted but 3 things:

1) 在复制选项运行时移动的进度条.我可以显示它,但它不会反应.

1) Progress-bar to move while the copy option is in motion. I can display it but it won't react.

我用这个来展示它:

self.p = ttk.Progressbar(self, orient=HORIZONTAL, length=300, mode='indeterminate')
self.p.grid(row=5)

然后在按下按钮时调用的另一个定义中启动它:

and then to initiate it in another def which is called upon a press of the button:

 self.p.start()

 shutil.copytree(self.source_direcotry0, self.cam0)
 shutil.copytree(self.source_direcotry1, self.cam1)
 shutil.copytree(self.source_direcotry2, self.cam2)

 self.p.stop()

不幸的是,复制发生了,但栏根本不动.

Unfortunately the copying occurs but the bar doesn't move at all.

2) 第二个问题与我在应用程序窗口底部显示的信息栏有关:

2) Second problem is connected to the information bar that I am displaying at the bottom of the app window:

self.status = Label(self.master, text="Waiting for process to start...", bd=1, relief=SUNKEN, anchor=W)
self.status.pack(side=BOTTOM, fill=X)

然后当在它的开头调用相同的复制 def 时,我有这个:

And then when the same copying def is called at the beginning of it I have this:

self.status['text'] = "Files are being copyied, have patience ;)".format(self.status)

而且状态没有改变,这很奇怪,因为在这个定义的结尾我也有相同的命令来改变状态,这个命令有效:

And the status is not changed which is weird as at the end of this def I also have same command to change the status and this one works:

self.status['text'] = "Files have been copyied".format(self.status)

3) 我似乎无法附上图片 我已经检查了各种不同的选项,但它们似乎都不起作用,此处显示的似乎试图显示某些内容(窗口变大)但图片是不可见:

3) I can't seem to attach a picture I have checked all kinds of different options and none of them seem to work, the one presented here seems like tries to display something (the window gets bigger) but the picture is not visible:

 self.img = ImageTk.PhotoImage(Image.open("az.png"))
 self.panel = Label(self, image=self.img, bg="#E6E6E6")
 self.display = self.img
 self.panel.grid(row=8)

我有点不确定为什么会这样,以防万一,为了了解更多信息,我在这里发布了完整的代码:

I am a bit unsure why it is happening like that, just in case and also for more info I am posting here the complete code:

from tkinter import *
from tkinter import ttk
import re
from tkinter import messagebox
from tkinter import filedialog
import ntpath
import os
import shutil
import tkinter.filedialog as fdialog
from send2trash import send2trash
from PIL import Image, ImageTk

#os.system('''/usr/bin/osascript -e 'tell app "Finder" to set frontmost of process "Python" to true' ''')


# Here, we are creating our class, Window, and inheriting from the Frame
# class. Frame is a class from the tkinter module. (see Lib/tkinter/__init__)

class Window(Frame):

    # Define settings upon initialization. Here you can specify
    def __init__(self, master=None):

        # parameters that you want to send through the Frame class. 
        Frame.__init__(self, master, bg="#E6E6E6")   

        #reference to the master widget, which is the tk window                 
        self.master = master

        #with that, we want to then run init_window, which doesn't yet exist
        self.init_window() 

    def copyy(self):

        self.status['text'] = "Files are being copyied, have patience ;)".format(self.status)


        self.source_direcotry0= '/Volumes/CAM0/DCIM/100HDDVR'
        self.source_direcotry1= '/Volumes/CAM1/DCIM/100HDDVR'
        self.source_direcotry2= '/Volumes/CAM2/DCIM/100HDDVR'
        self.source_direcotry3= '/Volumes/CAM3/DCIM/100HDDVR'
        self.source_direcotry4= '/Volumes/CAM4/DCIM/100HDDVR'
        self.source_direcotry5= '/Volumes/CAM5/DCIM/100HDDVR'
        self.source_direcotry6= '/Volumes/CAM6/DCIM/100HDDVR'
        self.source_direcotry7= '/Volumes/CAM7/DCIM/100HDDVR'
        self.source_direcotry8= '/Volumes/CAM8/DCIM/100HDDVR'
        self.source_direcotry9= '/Volumes/CAM9/DCIM/100HDDVR'
        self.source_direcotry10= '/Volumes/CAM10/DCIM/100HDDVR'
        self.source_direcotry11= '/Volumes/CAM11/DCIM/100HDDVR'

        self.path0="recording/CAM0"
        self.path1="recording/CAM1"
        self.path2="recording/CAM2"
        self.path3="recording/CAM3"
        self.path4="recording/CAM4"
        self.path5="recording/CAM5"
        self.path6="recording/CAM6"
        self.path7="recording/CAM7"
        self.path8="recording/CAM8"
        self.path9="recording/CAM9"
        self.path10="recording/CAM10"
        self.path11="recording/CAM11"

        self.cam0=os.path.join(self.Destination.get(), self.path0)
        self.cam1=os.path.join(self.Destination.get(), self.path1)
        self.cam2=os.path.join(self.Destination.get(), self.path2)
        self.cam3=os.path.join(self.Destination.get(), self.path3)
        self.cam4=os.path.join(self.Destination.get(), self.path4)
        self.cam5=os.path.join(self.Destination.get(), self.path5)
        self.cam6=os.path.join(self.Destination.get(), self.path6)
        self.cam7=os.path.join(self.Destination.get(), self.path7)
        self.cam8=os.path.join(self.Destination.get(), self.path8)
        self.cam9=os.path.join(self.Destination.get(), self.path9)
        self.cam10=os.path.join(self.Destination.get(), self.path10)
        self.cam11=os.path.join(self.Destination.get(), self.path11)

        self.p.start()

        shutil.copytree(self.source_direcotry0, self.cam0)
        shutil.copytree(self.source_direcotry1, self.cam1)
        shutil.copytree(self.source_direcotry2, self.cam2)
        # shutil.copytree(self.source_direcotry3, self.cam3)
        # shutil.copytree(self.source_direcotry4, self.cam4)
        # shutil.copytree(self.source_direcotry5, self.cam5)
        # shutil.copytree(self.source_direcotry6, self.cam6)
        # shutil.copytree(self.source_direcotry7, self.cam7)
        # shutil.copytree(self.source_direcotry8, self.cam8)
        # shutil.copytree(self.source_direcotry9, self.cam9)
        # shutil.copytree(self.source_direcotry10, self.cam10)
        # shutil.copytree(self.source_direcotry11, self.cam11)

        self.p.stop()

        self.status['text'] = "Files have been copyied".format(self.status)

    def deletee(self):
        send2trash('/Volumes/CAM0/DCIM')
        send2trash('/Volumes/CAM1/DCIM')
        send2trash('/Volumes/CAM2/DCIM')
        # send2trash('/Volumes/CAM3/DCIM')
        # send2trash('/Volumes/CAM4/DCIM')
        # send2trash('/Volumes/CAM5/DCIM')
        # send2trash('/Volumes/CAM6/DCIM')
        # send2trash('/Volumes/CAM7/DCIM')
        # send2trash('/Volumes/CAM8/DCIM')
        # send2trash('/Volumes/CAM9/DCIM')
        # send2trash('/Volumes/CAM10/DCIM')
        # send2trash('/Volumes/CAM11/DCIM')

        self.status['text'] = "Files have been moved to trash".format(self.status)


    def client_exit(self):
        exit()

    def about_popup(self):
        messagebox.showinfo("About", "This is software used to copy or delete files in bulk from the Absolute Zero VR camera")


    #Creation of init_window
    def init_window(self):

        self.Source=StringVar()
        self.Destination=StringVar()


        # changing the title of our master widget      
        self.master.title("AZ Data Extractor")

        # allowing the widget to take the full space of the root window
        self.pack(fill=BOTH, expand=1)

        #Creating the menu
        self.menubar = Menu(self.master)

        #Creating submenues
        self.filemenu = Menu(self.menubar, tearoff=0)
        self.filemenu.add_command(label="Exit", command=root.quit)
        self.menubar.add_cascade(label="File", menu=self.filemenu)

        self.helpmenu = Menu(self.menubar, tearoff=0)
        self.helpmenu.add_command(label="About", command=self.about_popup)
        self.menubar.add_cascade(label="Help", menu=self.helpmenu)

        #Displaying the menu
        root.config(menu=self.menubar)

        #Creating the  intro label
        l_instruction = Label(self, justify=CENTER, compound=TOP, text="Choose the destination for the copied files \n and press 'Go!' to start copyting", bg="#E6E6E6")
        l_instruction.grid(columnspan=2, ipady=10)

        l_instruction = Label(self, justify=CENTER, compound=TOP, text="Press 'Delete' to move all files \n from the camera to the trash", bg="#E6E6E6")
        l_instruction.grid(row=6, columnspan=2, ipady=10)

        # ttk.Style().configure('green/black.TButton', foreground='green', background='black')
        #Creating the button
        MyDestination=Entry(self, textvariable=self.Destination, bg="#E6E6E6")
        MyDestination.grid(row=2, columnspan=2, ipady=10)
        uploadButton = Button(self, text="Choose destination folder",command=lambda:self.Destination.set(fdialog.askdirectory()))
        uploadButton.grid(row=3, columnspan=2, ipady=10)
        goButton = Button(self, text="Go!",command=self.copyy)
        goButton.grid(row=4, columnspan=2, ipady=10)
        delButton = Button(self, text="Delete",command=self.deletee)
        delButton.grid(row=7, columnspan=2, ipady=10)

        self.p = ttk.Progressbar(self, orient=HORIZONTAL, length=300, mode='indeterminate')
        self.p.grid(row=5)

        self.img = ImageTk.PhotoImage(Image.open("az.png"))
        self.panel = Label(self, image=self.img, bg="#E6E6E6")
        self.display = self.img
        self.panel.grid(row=8)


        #resizing configuration
        self.grid_columnconfigure(0,weight=1)
        self.grid_columnconfigure(1,weight=1)
        self.grid_rowconfigure(0,weight=1)
        self.grid_rowconfigure(1,weight=1)
        self.grid_rowconfigure(2,weight=1)
        self.grid_rowconfigure(3,weight=1)
        self.grid_rowconfigure(4,weight=1)
        self.grid_rowconfigure(5,weight=1)
        self.grid_rowconfigure(6,weight=1)
        self.grid_rowconfigure(7,weight=1)
        self.grid_rowconfigure(8,weight=1)
        self.grid_rowconfigure(9,weight=1)
        self.grid_rowconfigure(10,weight=1)

        #status Bar
        self.status = Label(self.master, text="Waiting for process to start...", bd=1, relief=SUNKEN, anchor=W)
        self.status.pack(side=BOTTOM, fill=X)


# root window created. Here, that would be the only window, but you can later have windows within windows.
root = Tk()
root.resizable(width=False,height=False);
# root.configure(background='black');
# fm = Frame(root, width=300, height=200, bg="blue")
# fm.pack(side=TOP, expand=NO, fill=NONE)  
#root.geometry("230x340")



#creation of an instance
app = Window(root)

#mainloop 
root.mainloop()

就像同时出现的其他问题一样,我似乎无法更改按钮的背景颜色和输入字段周围的框架.我读到这可能是因为使用 MacOS 平台,是吗?有什么解决方法吗?

Just as and additional problem that came up in the mean time I can't seem to change background colour of the buttons and the frames around entry field. I read up it could be because using MacOS platform, could that be? Any workarounds?

推荐答案

我压缩了我在一个旧项目中工作的加载栏.我想出的唯一方法是在新线程中调用进度条处理调用,并将工作密集型函数从该线程调用到另一个新线程中.

I compacted the loading bar I got working in an older project of mine. The only way I had figured it out was to call the progress bar handling calls in a new thread and call the work-intensive functions from this thread into another new thread.

让单独的线程处理 UI 线程以外的 UI 元素是不好的做法,包括启动和停止进度条;但是它确实有效,而且我几个月来一直在使用这个项目来完成零问题的繁重处理.

It is bad practice to have a separate threads handling UI elements other than the UI thread, including starting and stopping a progress bar; however it does work and I've been using this project to do pretty heavy processing with zero issues for months now.

这里的进度条在一个小脚本中工作,在 W10 64 位上使用 Python 3.5.2

Here the progress bar is working in a small script, using Python 3.5.2 on W10 64-Bit

from tkinter import *
import tkinter.ttk as ttk
import threading
import time

class Main_Frame(object):
    def __init__(self, top=None):
        # save root reference
        self.top = top
        # set title bar
        self.top.title("Loading bar example")

        # start button calls the "initialization" function bar_init, you can pass a variable in here if desired
        self.start_button = ttk.Button(top, text='Start bar', command=lambda: self.bar_init(2500))
        self.start_button.pack()

        # the progress bar will be referenced in the "bar handling" and "work" threads
        self.load_bar = ttk.Progressbar(top)
        self.load_bar.pack()

        # run mainloop
        self.top.mainloop()

    def bar_init(self, var):
        # first layer of isolation, note var being passed along to the self.start_bar function
        # target is the function being started on a new thread, so the "bar handler" thread
        self.start_bar_thread = threading.Thread(target=self.start_bar, args=(var,))
        # start the bar handling thread
        self.start_bar_thread.start()

    def start_bar(self, var):
        # the load_bar needs to be configured for indeterminate amount of bouncing
        self.load_bar.config(mode='indeterminate', maximum=100, value=0)
        # 8 here is for speed of bounce
        self.load_bar.start(8)
        # start the work-intensive thread, again a var can be passed in here too if desired
        self.work_thread = threading.Thread(target=self.work_task, args=(var,))
        self.work_thread.start()
        # close the work thread
        self.work_thread.join()
        # stop the indeterminate bouncing
        self.load_bar.stop()
        # reconfigure the bar so it appears reset
        self.load_bar.config(value=0, maximum=0)

    def work_task(self, wait_time):
        for x in range(wait_time):
           time.sleep(0.001)

if __name__ == '__main__':
    # create root window
    root = Tk()
    # call Main_Frame class with reference to root as top
    Main_Frame(top=root)

这篇关于tkinter 中的进度条不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆