![](/img/trans.png)
[英]How can I combine tkinter and wxpython without freezing window - python?
[英]How can I show status of current task running and update the progressbar without freezing at same time in python 2 tkinter?
我的代碼顯示一個按鈕。 當按下按鈕時,出現文件對話框,要求用戶選擇文件(在消息框后)。 沒問題
我想更新進度條並顯示正在執行的當前任務的狀態時,會發生我的問題。
GUI凍結,並且僅在工作完成后更新進度欄和任務狀態。
或者,如果有人可以給我一個功能/類似的例子來做到這一點,請。
這是我正在使用的實際文件(Python 2):
# -*- coding: utf-8 -*-
import os
import Tkinter
import ttk
import tkMessageBox
import tkFileDialog
import base64
import threading
import Queue
import subprocess
import sys
import time
#here write my tasks
class Tareas():
def __init__(self, parent, row, column, columnspan):
self.parent = parent
self.length=200
self.value=0
self.maximum=100
self.interval=10
#I changed this from the original code - progressbar
self.barra_progreso = ttk.Progressbar(parent, orient=Tkinter.HORIZONTAL,
length = self.length,
mode="determinate",
value=self.value,
maximum=self.maximum)
self.barra_progreso.grid(row=row, column=column,
columnspan=columnspan)
#creating a thread to avoid gui freezing
self.thread = threading.Thread()
# status label tite (this does not change)
self.lbl_estado = Tkinter.Label(parent, text='STATUS:')
self.lbl_estado.grid(row=9, column=0, padx = 20, pady = 5)
# creating the status variable and declaring its value
self.estado_aplicacion = Tkinter.StringVar()
self.estado_aplicacion.set("Started, waiting for a task...")
# ***HERE I WANT DISPLAY CURRENT TASK RUNNING***
self.lbl_info_estado = Tkinter.Label(parent, text=self.estado_aplicacion.get(), textvariable=self.estado_aplicacion)
self.lbl_info_estado.grid(row=10, column=0, padx = 20, pady = 5)
def extraerDatosArchivo(self):
#task 1
print 'tarea 1'
#CHANGING TASK STATUS
self.estado_aplicacion.set('Seleccionando respaldo válido... (1/6)')
#displaying a messagebox to indicate to user choose a backup
tkMessageBox.showinfo('INFORMACIÓN', 'Select file to decrypt.')
#asking for a backup
archivo_respaldo = tkFileDialog.askopenfile(initialdir="/", title="Select file", filetypes=(("All files", "*.*"), ("All files2", "*.*")) )
#getting file
print 'archivo a desencriptar: ', archivo_respaldo
#checking if a file exists
if archivo_respaldo is None or not archivo_respaldo:
tkMessageBox.showerror('ERROR', 'No seleccionó nada.')
return None #stop task without close gui
###activating progressbar
if not self.thread.isAlive():
VALUE = self.barra_progreso["value"]
self.barra_progreso.configure(mode="indeterminate",
maximum=self.maximum,
value=VALUE)
self.barra_progreso.start(self.interval)
###
#CHANGING TASK STATUS
self.estado_aplicacion.set('Copiando clave privada... (2/6)')
#simulating long task
time.sleep(4)
print '2'
#CHANGING TASK STATUS
self.estado_aplicacion.set('Creando carpeta de trabajo... (3/6)')
#simulating long task
time.sleep(4)
print '3'
#CHANGING TASK STATUS
self.estado_aplicacion.set('TASKS FINISHED')
#displaying task finished succesfully
tkMessageBox.showinfo('INFORMATION', 'Done!.')
#gui tool, buttons, bla, bla, and more...
class GUI(Tkinter.Frame):
""" class to define tkinter GUI"""
def __init__(self, parent,):
Tkinter.Frame.__init__(self, master=parent)
"""desde aca se va controlar la progressbar"""
tareas = Tareas(parent, row=8, column=0, columnspan=2) #putting prog bar
#button for task 1
btn_extraer_datos_archivo = Tkinter.Button(parent, text = 'Select file', width=24, height=2, command=tareas.extraerDatosArchivo, state='normal')
btn_extraer_datos_archivo.grid(row=2, column=0, padx = 40, pady = 5)
root = Tkinter.Tk()
root.title('Extractor de datos 1.0')#title tool
root.minsize(200, 200)#bla bla...
root.resizable(0,0)#disabling resizing
herramienta = GUI(root)
root.mainloop()
我試圖找到可以幫助我解決這個問題的示例:
http://pythonexample.com/snippet/python/progresspy_rtogo_python
http://pythonexample.com/snippet/python/progresspy_c02t3x_python
https://www.python-forum.de/viewtopic.php?f=18&t=19150
和更多...
但是這些對我來說似乎仍然很困難,因為我是python的新手,而且我不知道如何在不凍結/崩潰GUI的情況下將tkfiledialog放入其中。
我創建與線程通信的隊列
self.queue = Queue.Queue()
並運行帶有將隊列作為參數的函數的線程。
self.thread = threading.Thread(target=self.my_function, args=(self.queue,))
線程將運行一些長時間運行的代碼,並使用隊列將消息發送到主線程。
它不會顯示任何消息框或更改窗口小部件中的值。
我在啟動線程之前先詢問文件-因此最終線程不使用任何tkinter的小部件或窗口。
主線程使用after()
定期運行檢查隊列的函數,如果有消息,它將獲取消息並更新窗口中的Label。 它還會更改Progressbar
值。 我使用mode="determinate"
並且不使用progressbar.start()
。
如果消息為"TASKS FINISHED"
則該功能不會再次檢查隊列。
代碼可以根據您的需要工作。
我刪除了代碼中的所有注釋,只有注釋。
import os
import Tkinter
import ttk
import tkMessageBox
import tkFileDialog
import threading
import Queue
#import sys
import time
class Tareas():
def __init__(self, parent, row, column, columnspan):
self.parent = parent
self.length=200
self.value=0
self.maximum=100
self.interval=10
self.barra_progreso = ttk.Progressbar(parent, orient=Tkinter.HORIZONTAL,
length = self.length,
mode="determinate",
value=self.value,
maximum=self.maximum)
self.barra_progreso.grid(row=row, column=column,
columnspan=columnspan)
self.lbl_estado = Tkinter.Label(parent, text='STATUS:')
self.lbl_estado.grid(row=9, column=0, padx = 20, pady = 5)
self.estado_aplicacion = Tkinter.StringVar()
self.estado_aplicacion.set("Started, waiting for a task...")
self.lbl_info_estado = Tkinter.Label(parent, text=self.estado_aplicacion.get(), textvariable=self.estado_aplicacion)
self.lbl_info_estado.grid(row=10, column=0, padx = 20, pady = 5)
def extraerDatosArchivo(self):
print 'tarea 1'
# do some job before you run thread
self.estado_aplicacion.set('Seleccionando respaldo válido... (1/6)')
tkMessageBox.showinfo('INFORMACIÓN', 'Select file to decrypt.')
archivo_respaldo = tkFileDialog.askopenfile(initialdir="/home/furas", title="Select file", filetypes=(("All files", "*.*"), ("All files2", "*.*")) )
print 'archivo a desencriptar: ', archivo_respaldo
if archivo_respaldo is None or not archivo_respaldo:
tkMessageBox.showerror('ERROR', 'No seleccionó nada.')
return
# --- (re)set progressbar ---
# set progressbar for 6+1 steps and `mode="determinate"`.
# because first step is already done so set value=1
self.barra_progreso.configure(#mode="indeterminate",
maximum=7,
value=1)
# don't start progresbar - I will change it manually
#self.barra_progreso.start()#self.interval)
# --- here starts thread ---
# create queue for communication with thread
self.queue = Queue.Queue()
# create thread and send queue as argument
self.thread = threading.Thread(target=self.my_function, args=(self.queue,))
# start thread
self.thread.start()
# start checking queue
self.check_queue()
def check_queue(self):
print("check queue")
# check if something in queue
# because `queue.get()` may block program when it waits for message
if not self.queue.empty():
# get message from queue
text = self.queue.get()
print("get text from queue:", text)
# change status
self.estado_aplicacion.set(text)
# TODO: you can update progressbar
self.barra_progreso['value'] += 1
# check if it is last message
if text == 'TASKS FINISHED':
# stop progersbar
self.barra_progreso.stop()
#displaying task finished succesfully
tkMessageBox.showinfo('INFORMATION', 'Done!.')
# exit without running `root.after()` again
return
# check queue after 200ms (0.2s) so mainloop will can do its job
root.after(200, self.check_queue)
def my_function(self, queue):
#CHANGING TASK STATUS
queue.put('Copiando clave privada... (2/6)')
#simulating long task
time.sleep(4)
print '2'
#CHANGING TASK STATUS
queue.put('Creando carpeta de trabajo... (3/6)')
#simulating long task
time.sleep(4)
print '3'
#CHANGING TASK STATUS
queue.put('Creando carpeta de trabajo... (4/6)')
#simulating long task
time.sleep(4)
print '4'
#CHANGING TASK STATUS
queue.put('Creando carpeta de trabajo... (5/6)')
#simulating long task
time.sleep(4)
print '5'
#CHANGING TASK STATUS
queue.put('Creando carpeta de trabajo... (6/6)')
#simulating long task
time.sleep(4)
print '6'
#CHANGING TASK STATUS
queue.put('TASKS FINISHED')
class GUI(Tkinter.Frame):
""" class to define tkinter GUI"""
def __init__(self, parent,):
Tkinter.Frame.__init__(self, master=parent)
tareas = Tareas(parent, row=8, column=0, columnspan=2)
btn_extraer_datos_archivo = Tkinter.Button(parent, text = 'Select file', width=24, height=2, command=tareas.extraerDatosArchivo, state='normal')
btn_extraer_datos_archivo.grid(row=2, column=0, padx = 40, pady = 5)
# --- main ---
root = Tkinter.Tk()
root.title('Extractor de datos 1.0')
root.minsize(200, 200)
root.resizable(0,0)
herramienta = GUI(root)
root.mainloop()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.