Оптимальный способ использовать tkinter и openpyxl для перебора электронной таблицы?

1

Я полный начинающий Python, пытаясь создать графический интерфейс, который позволяет пользователю выбирать файл Excel, из которого будут извлекаться и анализироваться некоторые данные. Для графического интерфейса я использую tkinter, а для операций Excel я использую openpyxl. Код, который у меня есть в настоящее время, но когда выбранный файл Excel большой, время выполнения глупо длинное (таблица с тысячами столбцов размером в 10 000 строк x 20 заняла около часа, чтобы пройти через итерацию, и время от времени становилось все медленнее). Кроме того, графический интерфейс перестает отвечать на все итерации. Я ранее делал программу практически идентично с помощью MATLAB, и она работала прекрасно, при этом весь процесс итерации занимал всего одну или две секунды, поэтому здесь что-то определенно напугано. Теперь я знаю, что это проблема со мной, а не с Python, поэтому я надеялся, что вы, ребята, могли бы указать мне в правильном направлении, как это исправить.

Вот несколько упрощенных примеров того, с чем я работаю, чтобы помочь проиллюстрировать мою ситуацию. Мне нужно пройти через каждую строку таблицы, проверить определенное значение в этой строке, чтобы увидеть, соответствует ли она тому, что я хочу, и если это произойдет, я храню некоторые данные из этой строки.

wb = openpyxl.load_workbook(filename = 'some_garbage.xlsx', read_only=True).worksheets[0]
all_data = wb.cell
desiredColor = 'Purple'
foodStorage = []

for row in range(2, wb.max_row + 1):
    print(row)
    if(all_data(row, 1).value == desiredColor):
        foodStorage.append(all_data(row,2))
        print('I found purple! Yee')

Изображение 174551

Должен ли я использовать модуль, отличный от openpyxl для этой задачи, или я просто делаю какую-то ошибку, которая позволяет openpyxl полностью функционировать? Должен ли я использовать потоки, чтобы ускорить процесс итерации, или чтобы окно моего графического интерфейса не переходило ко мне "Не реагировать" на меня, пока итерация делает свою вещь?

Я попытался найти вопросы по подобным вопросам, но я действительно не мог найти то, что искал, скорее всего, из-за моего отсутствия возможности поставить свою проблему в правильные слова. Итак, я заранее извиняюсь за то, что задал вопрос, на который, вероятно, ответили миллионы раз. Буду признателен за любую помощь, которую вы могли бы дать, и спасибо за ваше время.

Теги:
optimization
python-3.x
tkinter
openpyxl

1 ответ

-2

Я работаю над чем-то похожим, но с большими данными.

У меня была аналогичная проблема, и я предполагаю, что это происходит из-за того, что процессор пытается запустить как excel-итерацию, так и root.mainloop() в том же потоке, что не только замедляет процесс, но и зависает ваше приложение, -responsive. Чтобы это правильно работало, вам нужно будет вызвать функцию вашего работника (Iteration) в другом потоке, чем ваш root.mainloop(). Лучший способ сделать это - определить несколько классов для GUI, Worker и App и вызвать потоки функций Worker из вашего класса App, пока ваш графический интерфейс работает в другом цикле.

Простой пример для same-

import tkinter as tk
from tkinter import ttk,messagebox
import threading
import time

#base GUI Class
class GUI:
    def __init__(self, root, runCommand):
        mf = ttk.Frame(root, padding="5 5 5 5")
        mf.grid(column=0, row=0)
        mf.columnconfigure(0, weight=1)
        mf.rowconfigure(0, weight=1)

        # Global Values
        self.Fnm = tk.StringVar(root, "SearchFile.xlsx")
        self.Ncol = tk.StringVar(root, "D")
        self.Vcol = tk.StringVar(root, "C")
        # Label
        tk.Label(mf, text="File Name").grid(column=1, row=1, pady=6)
        tk.Label(mf, text="Name Col").grid(column=1, row=3, pady=6)
        tk.Label(mf, text="Value Col").grid(column=3, row=3, pady=6)

        # components
        self.fname = ttk.Entry(mf, width=18, textvariable=self.Fnm)
        self.nmCol = ttk.Entry(mf, width=6, textvariable=self.Ncol)
        self.valCol = ttk.Entry(mf, width=6, textvariable=self.Vcol)
        self.but = ttk.Button(mf, text="Refresh", command=runCommand)
        self.pgbar = ttk.Progressbar(mf, orient="horizontal", mode="determinate")

        # Design
        self.fname.grid(column=2, row=1, pady=3, columnspan=3)
        self.nmCol.grid(column=2, row=3, pady=3)
        self.valCol.grid(column=4, row=3, pady=3)
        self.but.grid(column=2, row=2, columnspan=2)
        self.pgbar.grid(column=1,row=4,columnspan=4)

    def refresh(self):
        pass

    def get(self):
        return [self.Fnm.get(), self.Ncol.get(), self.Vcol.get()]

#Base process Class
class Proc:
    def __init__(self, dets,pgbar,but):
        self.Fnm = dets[0]
        self.Ncol = dets[1]
        self.Vcol = dets[2]
        self.pg=pgbar
        self.butt=but

    def refresh(self):
        self.butt['state'] = 'disabled'
        self.pg.start()
        #ATTENTION:Enter Your process Code HERE
        for _ in range(5):
            time.sleep(2)#Longggg work
        self.pg.stop()
        #Any search/sort algorithm to be used
        #You can use self.pg.step() to be more specific for how the progress bar proceeds
        messagebox.showinfo("Process Done","Success")
        self.butt['state'] = 'enabled'

#Base Application Class
class App:
    def __init__(self, master):
        self.master = master
        self.gui = GUI(self.master, self.runit)

    def runit(self):
        self.search = Proc(self.gui.get(),self.gui.pgbar,self.gui.but)
        self.thread1 = threading.Thread(target=self.search.refresh)
        self.thread1.start()

def main():
    app = tk.Tk()
    gui = App(app)
    app.title("Refresh Search File")
    app.mainloop()

if __name__ == '__main__':
    main()

Что касается итерации по данным, вы можете проверить это для более эффективного кода.

Я не могу написать весь код здесь, поскольку он слишком длинный, поэтому, пожалуйста, обратитесь к ссылкам

  • 0
    Пожалуйста, воздержитесь от ссылок на внешние источники, не предоставив основную концепцию в ответе. Если по какой-либо причине ваши ссылки нарушат этот ответ, он больше не будет никому полезен.
  • 0
    Хорошо, Майк-СМТ, я добавлю здесь немного логики, но я бы действительно не стал размещать код, он очень и очень длинный, но если вы скажете, что он может быть лучше, я не буду возражать.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню