首页 > 解决方案 > How to update the progress bar value in a tkinter window from a Flask application which is in another thread?

问题描述

I have a Flask application that inserts some data in a database. While the insertion is in progress, I want a progress bar to show how many data were inserted (so, I use the determinate mode). Knowing that Flask and tkinter do not go together well proof, I decided to show the tkinter window in a separate thread, the main thread being the Flask application.

Here is my code so far

import tkinter as tk
from multiprocessing import Process
from tkinter.ttk import Progressbar, Button

import global_library
from application import config
from application.admin import add_match as a
from application.xml import create_string as cs
from application.xml import dl_xml_file as dl
from application.xml import xml_parsing as xp

def show_progress_window(low_end, high_end, match_count):
    root = tk.Tk()
    progress_bar = Progressbar(root, mode='determinate', orient='horizontal', length=200)
    progress_bar['maximum'] = high_end - low_end
    progress_bar['value'] = match_count
    progress_bar.pack()
    cancel_button = Button(root, text='Anulare')
    cancel_button.pack()
    root.mainloop()


def import_engine(low_end, high_end):
    file = config['DEFAULT']['PROTECTED_RESOURCE_PATH']
    for match_id in range(low_end, high_end + 1, 1):
        p = Process(target=show_progress_window, args=(low_end, high_end, match_id - low_end))
        p.start()
        p.join()
        params = cs.create_match_details_string(match_id)
        dl.download_xml_file(file, params, global_library.details_savepath)
        match_details = xp.parse_match_details_file(match_id)
        a.add_a_match(match_details[0], match_details[1], match_details[2], match_details[3], match_details[4],
                      match_details[5], match_details[6], match_details[7], match_details[8], match_details[9],
                      match_details[10], match_details[11], match_details[12], match_details[13], match_details[14],
                      match_details[15], match_details[16])

When I run this part, the progress bar updates, but I have to manually close the window for the importing to begin. After each import, the window appears, with the progress bar showing... progress. Obviously, this is from mainloop(). As obvious, I cannot suppres this method.

Where am I mistaking? What should I do so as I don't have to manually close the window at each iteration?

Later edit: a very important fact is that tkinter must run in the main thread. If it doesn't, the progress bar will not update no matter what.

标签: pythonmultithreadingflasktkintermultiprocessing

解决方案


Okay, my first answer made no sense. Have you tried taking the mainloop out of the function. Because now each time you call on the progress bar, it creates a new tk() instance.

something lke this:

root = tkinter.Tk()
# call your function and pass "root" to it as well
root.mainloop()

Edit 1: The code below provides two functions illustrating that it seems you can 'update' tkinter by starting a new mainloop. But that's not the case.

import tkinter as tk

def looptk(min,max,progress):
    root=tk.Tk()
    label = tk.Label(root, text=progress).pack()
    root.mainloop()
    print(id(root))


def looptk2(min,max,progress,root):
    label = tk.Label(root, text=progress).pack()
    print(id(root))

min = 0
max = 6
i = 0

while i < max:
    looptk(1,5,i)
    i += 1

root=tk.Tk()
min = 0
max = 6
i = 0
while i < max:
    looptk2(1,5,i,root)
    i += 1
root.mainloop()

Edit 2:

Here is where you call the mainloop several times:

for match_id in range(low_end, high_end + 1, 1):
        p = Process(target=show_progress_window, args=(low_end, high_end, match_id - low_end))

To fix it you need to create a mainloop before that for loop. Change it to something like this:

root = tk.tk()
for match_id in range(low_end, high_end + 1, 1):
    p = Process(target=show_progress_window, args=(low_end, high_end, match_id - low_end,root))

root.mainloop()

Don't forget to add "root" between the brackets of the function show_progress_window(Add root to the end). And remove the mainloop from the function.


推荐阅读