Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
335 views
in Technique[技术] by (71.8m points)

python - Start/stop a while loop?

I'm trying to write a program that makes a list of all .xml files in a folder, then copies them to another directory and deletes from the original directory. This part of the program works fine. I want to make it so that I can click a button in the GUI and have it scan and process folders until I press a button to turn it off. Again, turning it on is not a problem, but trying to stop it has me stumped. I'd like it to wait some time in between but using time.sleep(x) freezes the entire program and doesn't let me input any more commands until it's stopped sleeping, only for it to process and then sleep again. Any suggestions on how to essentially start/stop a while loop from a GUI tkinter button?

Code is below:

#! python3
import glob
import time
import shutil
import os
import sys
import datetime
import errno
import re
import fnmatch
import tkinter # copy tcl8.5 and tk8.5 to folder
from tkinter import ttk
import sched



flag = 0

with open("config.ini") as f:
    g = f.readlines()
    sourcedir = g[0][10:-1]
    ICdir = g[1][13:-1]
    BUdir = g[2][13:-1]
    LOGdir = g[3][8:-1]
    el = g[4][3:-1]

# reads directories from config.ini

h = len(sourcedir)
# obtains length of address, used later on

def exemel():
    m = sorted(glob.glob(sourcedir+"/*.xml"), key=os.path.getmtime)
    n = len(m)
    if n == 0:
        print("none left")
    for item in range(n):
        try:
            m = sorted(glob.glob(sourcedir+"/*.xml"), key=os.path.getmtime)
            n = len(m)
            if n == 0:
                print("none left")
            global flag
            if flag == 5:
                flag = 0
                item = item + 1
            with FileLock(m[item]):
                k = h - len(m[item])
                g = m[item][k:] 
                shutil.copy(m[item], ICdir)
                shutil.move(m[item], BUdir)
                print(m[item] + " successfully processed.")
                dated = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                if os.path.exists(LOGdir):
                    with open(LOGdir, "a") as logging:
                        logline = '
' + '"' + g[1:] + '", #' + dated + "# copied"
                        logging.write(logline)
                else:
                    with open(LOGdir, "w") as logging:
                        logline = '"' + g[1:] + '", #' + dated + "# copied"
                        logging.write(logline)


        except PermissionError:
            print("File in use, waiting..")
            time.sleep(1.5)
            flag += 1
            continue
        except shutil.Error as e:
            os.remove(ICdir + g)
            os.remove(BUdir + g)
            print("Existing files removed..")
            dated = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            if el == "1":
                if os.path.exists(LOGdir):
                    with open(LOGdir, "a") as logging:
                        logline = '
' + '"' + g[1:] + '", #' + dated + "# overwritten"
                        logging.write(logline)
                else:
                    with open(LOGdir, "w") as logging:
                        logline = '"' + g[1:] + '", #' + dated + "# overwritten"
                        logging.write(logline)
        except IndexError:
            item = 0
            continue
        except SystemExit:
            break
        except KeyboardInterrupt:
            break



def prunt():
    print("ZES")


def config():
    print("config")

def stop():
    print("stop")
    global x
    x = False
    global STOP
    STOP = True



s = sched.scheduler(time.time, time.sleep)

def run_periodically(start, end, interval, func):
    event_time = start
    while event_time < end:
        s.enterabs(event_time, 0, func, ())
        event_time += interval
    s.run()


def starter():
    run_periodically(time.time(), time.time()+600, 60, exemel)



### GUI BEGIN ###


root = tkinter.Tk()
root.title("XML Wizard")

mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=("N","W", "E", "S"))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)


sourceEntry = ttk.Entry(mainframe, width=50, textvariable=sourcedir)
sourceEntry.grid(column=2, row = 1, columnspan=2)
ttk.Label(mainframe, text="Source Directory:").grid(column=1, row=1, sticky="W")

BackupEntry = ttk.Entry(mainframe, width=50, textvariable=BUdir)
BackupEntry.grid(column=2, row = 2, columnspan=2)
ttk.Label(mainframe, text="Backup Directory:").grid(column=1, row=2, sticky="W")

ImportEntry = ttk.Entry(mainframe, width=50, textvariable=ICdir)
ImportEntry.grid(column=2, row = 3, columnspan=2)
ttk.Label(mainframe, text="Import Directory:").grid(column=1, row=3, sticky="W")

ttk.Button(mainframe, text="Go", command=starter).grid(column=4, row=5, sticky="W")
ttk.Button(mainframe, text="Save Config", command=config).grid(column=5, row=4, sticky="W")
ttk.Button(mainframe, text="Load Config", command=config).grid(column=5, row=3, sticky="W")
ttk.Button(mainframe, text="Stop", command=stop).grid(column=3, row=5, sticky="W")

root.mainloop()

FileLock function was found on here and works perfectly if you're wondering but I left it out for space/readibility. I know my code is sloppy but I've only just begun programming.

Any recommendations/alternate methods are very welcome!

btw: exemel is the function that I want to loop!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The basic idea is to have a function that processes a single file, and then you use the event loop to call that function repeatedly until there are no more files to process. You do this with the after command.

Inside your function you can also check for a global flag. If the flag is set, the function does no work, and doesn't schedule any work to be done. Use your pause button button to set the flag. Once you set this up, call your function once and it will continue to run until all files have been processed.

For example:

def do_one_file():
    global files_to_process, paused

    if not paused:
        file = files_to_process.pop()
            ... do some work here ...

    if len(files_to_process) > 0:
        root.after(10, do_one_file)

This will check to see if you've paused the work. If you have not, it will pull one file off of the stack of files to process and process it. Then, if there's more work to be done, it schedules the next file to be processed in 10ms.

Assuming that the actual work takes only a few hundred ms, your GUI will remain responsive and the copying happens "in the background". I put that in quotes because it all happens on the main thread rather than a background thread or process, but it happens in those moments when the GUI is doing nothing else (which is actually most of the time).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...