HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Tkinter file searching program

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
programfiletkintersearching

Problem

This is my first relatively big program. First it shows an askdirectory() screen to get the path. It gets all subfolders of that path and appends them to a list. It checks every folders' items if they are wanted file types by checking extensions and puts them into a proper sqlite table. After all files written to a database file, a GUI appears to get what user wants to search. After clicking search_button it gets my_entry and checks if it's in database. If yes, appends it to a list and after all database is searched, it shows results in a listbox.

There are two lists because I couldn't find the way to get path while only writing file names to a list. So one of the list is shown and only have file names, the other one is hidden and contains whole path for that file.

My code is working relatively slow while writing to a database or reading from it but my real problem is, this program should search 3TB of data which contain lots of folders, files etc.. So when I try to show hundreds (sometimes it is thousands) of items in listBox, GUI freezes. I cannot scroll up/down or open folders by double clicking on their names.

-
How can I handle that problem? Is there a way to do it with Tkinter or should I use something else?

-
Any tips on style?

-
Lastly, about writing to/reading from database performance, should I use threading?

```
#--coding: utf8--

import os
import sys
import time
import sqlite3
import tkinter
from tkinter import ttk
from tkinter import filedialog
from tkinter import messagebox
from win32com.shell import shell, shellcon

class Prompt(tkinter.Frame):
def search_button(self):
reading.reader() ##to get data from database tables
self.my_entry = self.ent.get()
if self.my_entry:
for line in reading.lines:
if self.my_entry.lower() in line.split("/")[-1].lower(): ##if entry from textbox in file/path name
self.results.append(line)
self.shown_list()
se

Solution

In looking at your code, there are a few things I would do:

  • Subclass TK.. class MainGUI(Tk):



  • Attach all gui components to this class.... your frame for example.



  • Add a queue and a polling method for GUI updates to the MainGUI class (this may help fix your freezing issue). You can use the TK.after method to ask the mainloop to do this periodically.



  • Do the heavy lifting items such as db reads, filesystem, etc in a separate thread if they block too long, but make sure they don't update the GUI directly from that thread, you can pass a reference to the GUI to them and they should place a callback on the updateq for the main loop to execute as it runs a polling cycle.



  • Check the code for pep8 compliance.



Here is an example of how I have done GUI's using TKinter:

class MainGUI(Tk):
    """ The GUI """

    def __init__(self):
        super().__init__()
        self.updateq = queue.Queue()

        # Build main components

        # Layout components

        # Key bindings

        self.poll()
        self.mainloop()

    def poll(self):
        """ Polls the Queue for the arrival of various callbacks """
        # You may want to process more or less callbacks each cycle...
        # here it uses 100 as a maximum
        for i in range(100):
            if self.updateq.empty():
                break

            callback, args = self.updateq.get()
            if args:
                callback(args)
            else:
                callback()

        # Recursive call
        self.after(50, self.poll)

Code Snippets

class MainGUI(Tk):
    """ The GUI """

    def __init__(self):
        super().__init__()
        self.updateq = queue.Queue()

        # Build main components

        # Layout components

        # Key bindings

        self.poll()
        self.mainloop()

    def poll(self):
        """ Polls the Queue for the arrival of various callbacks """
        # You may want to process more or less callbacks each cycle...
        # here it uses 100 as a maximum
        for i in range(100):
            if self.updateq.empty():
                break

            callback, args = self.updateq.get()
            if args:
                callback(args)
            else:
                callback()

        # Recursive call
        self.after(50, self.poll)

Context

StackExchange Code Review Q#39198, answer score: 5

Revisions (0)

No revisions yet.