如何在 python 2 tkinter 中显示当前任务运行的状态并更新进度条而不同时冻结?

2024-01-03

我的代码显示一个按钮。当按钮被按下时, 出现一个文件对话框要求用户选择一个文件 (在消息框之后)。这里没问题。

当我想更新进度条时出现问题 并显示当前正在执行的任务的状态。

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

我试图找到可以帮助我的例子:

如何将进度条连接到函数? https://stackoverflow.com/questions/15323574/how-to-connect-a-progress-bar-to-a-function

https://reformatcode.com/code/python/tkinter-how-to-use-threads-to-preventing-main-event-loop-from-quotfreezingquot https://reformatcode.com/code/python/tkinter-how-to-use-threads-to-preventing-main-event-loop-from-quotfreezingquot

http://pythonexample.com/snippet/python/progresspy_rtogo_python http://pythonexample.com/snippet/python/progresspy_rtogo_python

http://pythonexample.com/snippet/python/progresspy_c02t3x_python http://pythonexample.com/snippet/python/progresspy_c02t3x_python

https://www.reich13.tech/python-how-to-get-progressbar-start-info-from-one-window-class-to-other-5a26adfbcb90451297178f35 https://www.reich13.tech/python-how-to-get-progressbar-start-info-from-one-window-class-to-other-5a26adfbcb90451297178f35

和更多...

但这些对我来说似乎还很困难,因为我是 python 的新手, 我不知道如何在不冻结/崩溃 GUI 的情况下将 tkfiledialog 放入其中。


我创建队列用于与线程通信

self.queue = Queue.Queue()

并使用以队列作为参数的函数运行线程。

self.thread = threading.Thread(target=self.my_function, args=(self.queue,))

线程将运行一些长时间运行的代码并使用队列向主线程发送消息。
它会NOT显示任何消息框或更改小部件中的值。

我在启动线程之前请求文件 - 所以最终线程不使用任何 tkinter 的小部件或窗口。

主线程使用after()定期运行检查队列的函数,如果有消息,它会获取消息并更新窗口中的标签。它还改变了价值Progressbar. I use mode="determinate"并且不要使用progressbar.start().

如果消息是"TASKS FINISHED"then 函数不会再次检查队列。


代码可以按照您可能需要的方式工作。

我删除了你在代码中的所有评论,只有我的评论。

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()
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 python 2 tkinter 中显示当前任务运行的状态并更新进度条而不同时冻结? 的相关文章

  • 使用 python 中的公式函数使从 Excel 中提取的值的百分比相等

    import xlrd numpy excel Users Bob Desktop wb1 xlrd open workbook excel assignment3 xlsx sh1 wb1 sheet by index 0 colA co
  • 为什么删除临时文件时出现WindowsError?

    我创建了一个临时文件 向创建的文件添加了一些数据 已保存 然后尝试将其删除 但我越来越WindowsError 编辑后我已关闭该文件 如何检查哪个其他进程正在访问该文件 C Documents and Settings Administra
  • 如何检查python xlrd库中的excel文件是否有效

    有什么办法与xlrd库来检查您使用的文件是否是有效的 Excel 文件 我知道还有其他库可以检查文件头 我可以使用文件扩展名检查 但为了多平台性我想知道是否有任何我可以使用的功能xlrd库本身在尝试打开文件时可能会返回类似 false 的内
  • 检查 Python 中的可迭代对象中的所有元素的谓词是否计算为 true

    我很确定有一个常见的习语 但我无法通过谷歌搜索找到它 这是我想做的 用Java Applies the predicate to all elements of the iterable and returns true if all ev
  • Python 中的流式传输管道

    我正在尝试使用 Python 将 vmstat 的输出转换为 CSV 文件 因此我使用类似的方法转换为 CSV 并将日期和时间添加为列 vmstat 5 python myscript py gt gt vmstat log 我遇到的问题是
  • 工作日重新订购 Pandas 系列

    使用 Pandas 我提取了一个 CSV 文件 然后创建了一系列数据来找出一周中哪几天崩溃最多 crashes by day bc DAY OF WEEK value counts 然后我将其绘制出来 但当然它按照与该系列相同的排名顺序绘制
  • sklearn 中的 pca.inverse_transform

    将我的数据拟合后 X 我的数据 pca PCA n components 1 pca fit X X pca pca fit transform X 现在 X pca 具有一维 当我根据定义执行逆变换时 它不是应该返回原始数据 即 X 二维
  • 如果未引发异常,则通过 Python 单元测试

    在Python中unittest框架 是否有一种方法可以在未引发异常的情况下通过单元测试 否则会因 AssertRaise 而失败 如果我正确理解你的问题 你could做这样的事情 def test does not raise on va
  • 没有名为 StringIO 的模块

    我有Python 3 6 我想从另一个名为 run py 的 python 文件执行名为 operation py 的 python 文件 In operation py I do from cStringIO import StringI
  • 在 Django OAuth Toolkit 中安全创建新应用程序

    如何将 IsAdminUser 权限添加到 Django OAuth Toolkit 中的 o applications 视图 REST FRAMEWORK DEFAULT PERMISSION CLASSES rest framework
  • 在 matplotlib 中的极坐标图上移动径向刻度标签

    From matplotlib 示例 http matplotlib org examples pylab examples polar demo html import numpy as np import seaborn as sbs
  • Django 的 request.FILES 出现 UnicodeDecodeError

    我在视图调用中有以下代码 def view request body u for filename f in request FILES items body body Filename filename n f read n 在某些情况下
  • Python新式类和__subclasses__函数

    有人可以向我解释为什么这有效 在 Python 2 5 中 class Foo object pass class Bar Foo pass print Foo subclasses 但这不是 class Foo pass class Ba
  • 使用 python 绘制正值小提琴图

    我发现小提琴图信息丰富且有用 我使用 python 库 seaborn 然而 当应用于正值时 它们几乎总是在低端显示负值 我发现这确实具有误导性 尤其是在处理现实数据集时 在seaborn的官方文档中https seaborn pydata
  • 使用Python计算目录的大小?

    在我重新发明这个特殊的轮子之前 有没有人有一个很好的例程来使用 Python 计算目录的大小 如果例程能够很好地以 Mb Gb 等格式格式化大小 那就太好了 这会遍历所有子目录 总结文件大小 import os def get size s
  • Geodjango距离查询未检索到正确的结果

    我正在尝试根据地理位置的接近程度来检索一些帖子 正如您在代码中看到的 我正在使用 GeoDjango 并且代码在视图中执行 问题是距离过滤器似乎被完全忽略了 当我检查查询集上的距离时 我得到了预期距离 1m 和 18km 但 18km 的帖
  • SMTP_SSL SSLError: [SSL: UNKNOWN_PROTOCOL] 未知协议 (_ssl.c:590)

    此问题与 smtplib 的 SMTP SSL 连接有关 当与 SMTP 无 ssl 连接时 它正在工作 在 SMTP SSL 中尝试相同的主机和端口时 出现错误 该错误仅基于主机 gmail 设置也工作正常 请检查下面的示例 如果 Out
  • ANTLR 获取并拆分词法分析器内容

    首先 对我的英语感到抱歉 我还在学习 我为我的框架编写 Python 模块 用于解析 CSS 文件 我尝试了 regex ply python 词法分析器和解析器 但我发现自己在 ANTLR 中 第一次尝试 我需要解析 CSS 文件中的注释
  • 双击打开 ipython 笔记本

    相关文章 通过双击 osx 打开 ipython 笔记本 https stackoverflow com questions 16158893 open an ipython notebook via double click on osx
  • 如何为不同操作系统/Python 版本编译 Python C/C++ 扩展?

    我注意到一些成熟的Python库已经为大多数架构 Win32 Win amd64 MacOS 和Python版本提供了预编译版本 针对不同环境交叉编译扩展的标准方法是什么 葡萄酒 虚拟机 众包 我们使用虚拟机和Hudson http hud

随机推荐