繁体   English   中英

tkinter 中的进度条不起作用

[英]Progress bar in tkinter not working

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

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

我用它来展示它:

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

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

 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()

不幸的是,复制发生了,但条形图根本不动。

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

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 时,我有这个:

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

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

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

3)我似乎无法附上图片我检查了各种不同的选项,但似乎没有一个起作用,这里显示的似乎试图显示一些东西(窗口变大)但图片不可见:

 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)

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

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 平台,是吗? 任何解决方法?

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

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

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

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)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM