how to stop opening the same window multiple time when the button clicked for below code. in this I'm using multiprocessing.
on button click event I'm getting issue like screenshot
github repo
root = Tk()
root.title("PDF Reader")
root.geometry("500x300+500+300")
root.maxsize(width=None, height=None)
root.resizable(False, False)
def dostuff():
if (__name__ == "__main__"):
try:
folder = folderPath.get()
if folder != "":
if (os.path.exists(folder)):
run_btn['state'] = DISABLED
msg = "Please wait... Process being done.\n Dont close the app."
label = Label(root, text=msg, foreground="red")
label.grid(row=5, column=0, padx=20)
# label.pack()
label.update()
#root.protocol("WM_DELETE_WINDOW", on_exit)
root.protocol("WM_DELETE_WINDOW", disable_event)
pdfs_list = get_listof_files(folder, "pdf")
with multiprocessing.Manager() as manager:
failed = manager.list()
if pdfs_list:
p = multiprocessing.Pool(5)
p.map(partial(get_total_txt, failed),
pdfs_list)
# p.close()
# Process.join(p)
# print(failed)
label.destroy()
suss_files_count = len(pdfs_list)-len(failed)
print("Out of {} files {} Succeeded and {} files found without data {} Files Without Grid Numbers and {} loaded.".format(
len(pdfs_list), suss_files_count, len(
failed), len(No_grid_number),
str(round(suss_files_count/(len(pdfs_list))*100, 2))+"%"))
msg = "\nProcess has been Completed Sucessfully..!\n Out of {} files {} Succeeded and {} files found without data.\n Please check Log for More info.".format(
len(pdfs_list), suss_files_count, len(
failed), len(No_grid_number))
label = Label(root, text="", foreground="green")
label.grid(row=5, column=0, padx=20)
# label.pack()
label.update()
label = Label(root, text=msg, foreground="green")
label.grid(row=5, column=0, padx=20)
# label.pack()
label.update()
time.sleep(5)
label.destroy()
end_time = datetime.now()
print('Duration: {} Minutes'.format(end_time - start_time))
run_btn['state'] = NORMAL
else:
messagebox.showerror(
"Path Not Found", "Selected path or directory doesn't exists: "+folder)
else:
messagebox.showwarning("Warning", "Please Select path")
# print(folder)
except AttributeError as attbe:
messagebox.showerror("AttributeError", str(attbe))
except FileNotFoundError as fne:
messagebox.showerror("TypeError", str(fne))
run_btn['state'] = NORMAL
#print(fne, folder)
except TypeError as TError:
messagebox.showerror("TypeError", str(TError))
run_btn['state'] = NORMAL
folderPath = StringVar()
a = Label(root, text="\nChoose Path:", font=('Arial'))
a.grid(row=0, column=0)
e = Entry(root, textvariable=folderPath, width=50)
e.grid(row=3, column=0, padx=35)
btn_browse = ttk.Button(root, text="Browse", command=getFolderPath, padding=5)
btn_browse.grid(row=3, column=1)
""""whenever the button is clicked, a new thread will be created and started """
run_btn = Button(root, text="Run", command=lambda: Thread(target=dostuff).start(),
width=30, height=2, padx=10)
run_btn.grid(row=4, column=0)
# root.protocol("WM_DELETE_WINDOW", on_exit)
# root.protocol("WM_DELETE_WINDOW", lambda: (
# run_btn.config(state="disabled"), root.destroy()))
root.lift()
root.mainloop()
Here's the kind of structure you need. This still doesn't work, because I don't have the functions in your module and there are some errors in your code, but this shows the structure:
import os
import glob
import multiprocessing
from tkinter import *
def get_total_txt(f,pdf):
f.append(pdf)
def get_listof_files(folder,ext):
return glob.glob( folder+"/*."+ext)
def getFolderPath():
folder_selected = filedialog.askdirectory(initialdir="")
folderPath.set(folder_selected)
def on_exit():
"""When you click to exit, this function is called"""
if run_btn['state'] == DISABLED:
if messagebox.askyesno("Exit", "Are you want to quit the application? Currently process being in running state."):
root.destroy()
sys.exit(0)
else:
if messagebox.askyesno("Exit", "Are you want to quit the application?"):
root.destroy()
def disable_event():
messagebox.showinfo( "Processing", "Please wait until process being done.")
def dostuff():
folder = folderPath.get()
if folder != "":
if os.path.exists(folder):
run_btn['state'] = DISABLED
msg = "Please wait... Process being done.\n Dont close the app."
label = Label(root, text=msg, foreground="red")
label.grid(row=5, column=0, padx=20)
label.update()
#root.protocol("WM_DELETE_WINDOW", on_exit)
root.protocol("WM_DELETE_WINDOW", disable_event)
pdfs_list = get_listof_files(folder, "pdf")
with multiprocessing.Manager() as manager:
failed = manager.list()
if pdfs_list:
p = multiprocessing.Pool(5)
p.map(partial(get_total_txt, failed),
pdfs_list)
label.destroy()
suss_files_count = len(pdfs_list)-len(failed)
print("Out of {} files {} Succeeded and {} files found without data {} Files Without Grid Numbers and {} loaded.".format(
len(pdfs_list), suss_files_count, len(
failed), len(No_grid_number),
str(round(suss_files_count/(len(pdfs_list))*100, 2))+"%"))
msg = "\nProcess has been Completed Sucessfully..!\n Out of {} files {} Succeeded and {} files found without data.\n Please check Log for More info.".format(
len(pdfs_list), suss_files_count, len(
failed), len(No_grid_number))
label = Label(root, text="", foreground="green")
label.grid(row=5, column=0, padx=20)
# label.pack()
label.update()
label = Label(root, text=msg, foreground="green")
label.grid(row=5, column=0, padx=20)
# label.pack()
label.update()
time.sleep(5)
label.destroy()
end_time = datetime.now()
print('Duration: {} Minutes'.format(end_time - start_time))
run_btn['state'] = NORMAL
else:
messagebox.showerror(
"Path Not Found", "Selected path or directory doesn't exists: "+folder)
else:
messagebox.showwarning("Warning", "Please Select path")
def main():
global root
global folderPath
global run_btn
root = Tk()
root.title("PDF Reader")
root.geometry("500x300+500+300")
root.maxsize(width=None, height=None)
root.resizable(False, False)
folderPath = StringVar()
a = Label(root, text="\nChoose Path:", font=('Arial'))
a.grid(row=0, column=0)
e = Entry(root, textvariable=folderPath, width=50)
e.grid(row=3, column=0, padx=35)
#btn_browse = ttk.Button(root, text="Browse", command=getFolderPath, padding=5)
btn_browse = Button(root, text="Browse", command=getFolderPath)
btn_browse.grid(row=3, column=1)
""""whenever the button is clicked, a new thread will be created and started """
run_btn = Button(root, text="Run", command=dostuff, width=30, height=2, padx=10)
run_btn.grid(row=4, column=0)
# root.protocol("WM_DELETE_WINDOW", on_exit)
# root.protocol("WM_DELETE_WINDOW", lambda: (
# run_btn.config(state="disabled"), root.destroy()))
root.lift()
root.mainloop()
if __name__ == "__main__":
main()
Related
Trying to write a little program where you type in a Tkinter Entry widget and if you don't type for 5 seconds it deletes everything. The best I can do is have it delete everything on the first key pressed after the five seconds elapses, but I can't figure out how to get it to do it without that extra key press.
import time
from tkinter import *
def click(key):
global click_before_last_click, last_click
# print(key.char)
click_before_last_click = last_click
last_click = time.time()
# print(click_before_last_click)
# print(last_click)
delete_shit()
def disappearing_text_start():
global click_before_last_click, last_click
click_before_last_click = time.time()
last_click = time.time()
entry.delete(1.0, END)
entry.bind("<Key>", click)
def disappearing_text_end():
text_file = open("result.txt", "w")
text_file.write(entry.get(1.0, END))
text_file.close()
entry.delete(1.0, END)
def delete_shit():
if last_click > click_before_last_click + 5:
print("TOO LONG")
entry.delete(1.0, END)
if __name__ == "__main__":
click_before_last_click = time.time()
last_click = time.time()
window = Tk()
window.title("Disappearing Text")
window.config(padx=50, pady=20, bg="#D3D3D3")
title_label = Label(text="Disappearing Text App", fg="black", bg="#D3D3D3", font=("Courier", 24))
title_label.grid(column=1, row=0, columnspan=2)
label = Label(text="Click start to begin, and end to save your text. "
"If you stop typing for 5 seconds, you lose everything.",
bg="#D3D3D3", font=("Courier", 14))
label.grid(column=1, row=1, columnspan=2)
entry = Text(width=100, height=30)
entry.grid(column=1, columnspan=2, row=3)
start_button = Button(text="Start", command=disappearing_text_start)
start_button.grid(column=1, row=4, pady=20)
end_button = Button(text="Save", command=disappearing_text_end)
end_button.grid(column=2, row=4, pady=20)
window.mainloop()
You can use after to delete the characters after the time interval. Each time the user presses a key, delete the old scheduled function and then reschedule it.
Also, FWIW, you've used an index of 1.0 which is invalid. Tkinter will accept it, but an index is a string rather than a floating point number.
Let's start by writing a function that will schedule the text to be deleted in 5 seconds. It will also cancel any pending job, effectively resetting the timer to zero. It needs to accept an event parameter since it will be called from a key binding.
after_id = None
def schedule_delete(event=None):
global after_id
if after_id:
window.after_cancel(after_id)
after_id = window.after(5000, delete_shit)
Next, arrange for this to be called when the user clicks the "start" button. disappearing_text_start might look something like this:
def disappearing_text_start():
schedule_delete()
entry.delete("1.0", END)
You can then call this bind command once in the main body of of your program to have reschedule_delete called on every keypress:
entry.bind("<Any-KeyPress>", reschedule_delete)
Finally, we need to cancel any pending job when the user clicks the "stop" button:
def disappearing_text_end():
global after_id
if after_id:
window.after_cancel(after_id)
after_id = None
... the rest of your code here ...
Here's a complete working example:
from tkinter import *
def click(key):
schedule_delete()
def disappearing_text_start():
schedule_delete()
entry.delete("1.0", END)
def schedule_delete(event=None):
global after_id
if after_id:
window.after_cancel(after_id)
after_id = window.after(5000, delete_shit)
def disappearing_text_end():
global after_id
if after_id:
window.after_cancel(after_id)
after_id = None
text_file = open("result.txt", "w")
text_file.write(entry.get(1.0, END))
text_file.close()
entry.delete("1.0", END)
def delete_shit():
entry.delete("1.0", END)
if __name__ == "__main__":
# this is used to keep track of the scheduled function call
after_id = None
window = Tk()
window.title("Disappearing Text")
window.config(padx=50, pady=20, bg="#D3D3D3")
title_label = Label(text="Disappearing Text App", fg="black", bg="#D3D3D3", font=("Courier", 24))
title_label.grid(column=1, row=0, columnspan=2)
label = Label(text="Click start to begin, and end to save your text. "
"If you stop typing for 5 seconds, you lose everything.",
bg="#D3D3D3", font=("Courier", 14))
label.grid(column=1, row=1, columnspan=2)
entry = Text(width=100, height=30)
entry.grid(column=1, columnspan=2, row=3)
start_button = Button(text="Start", command=disappearing_text_start)
start_button.grid(column=1, row=4, pady=20)
end_button = Button(text="Save", command=disappearing_text_end)
end_button.grid(column=2, row=4, pady=20)
entry.bind("<Any-KeyPress>", schedule_delete)
window.mainloop()
I am making a GUI in Tkinter and the code prints some attributes of a class.
However, something makes it print the attributes from the current instance but also from the previous ones (sorry if the jargon is wrong, I'm really new to this).
So in the Todo-list GUI I have created, I will enter a task and specify some attributes, then print all the attributes.
The task name is then displayed in a listbox and all the attributes of the task should be printed to terminal at the same time - however, this is where it will print the current attributes which I have just entered but also the attributes from the previously added task.
This is the code and the print command is in the def show_task(): function.
from tkcalendar import * # Calendar module
import tkinter.messagebox # Import the messagebox module
task_list = []
task_types = ['Sparetime', 'School', 'Work']
class Task:
def __init__(self, n, type_, i, m, p, h): #(h, w=8, p, u, n, v):
self.name = n
self.type = type_
self.impact = i
self.manageability = m
self.proximity = p
self.hours = h
#self.connectivity = c
##self.work = w ##hours of work per day
##self.urgency = u
##self.note = n
##self.value = v
def show_tasks():
# for widget in task_frame.winfo_children():
# widget.destroy()
for task in task_list:
#listbox_tasks.insert(tkinter.END, *task_list) #(task_frame, text=f'{task.name} \n Type: {task.type} | Impact: {task.impact}| Manageability: {task.manageability} | Proximity: {task.proximity}').pack(fill='x')
print(
'Task:'+task.name +
'\n' +
'Type:' + task.type + '\n' +
'Impact:' + task.impact + '\n' +
'Manageability:' + task.manageability + '\n' +
'Proximity(Deadline):' + task.proximity + '\n' +
'Hours:' + task.hours + '\n'
)
def open_add_task():
taskwin = Toplevel(root)
taskwin.focus_force()
#TITLE
titlelabel = Label(taskwin, text='Title task concisely:').grid(column=1, row=0)
name_entry = Entry(taskwin, width=40, justify='center')
name_entry.grid(column=1, row=1)
#TYPE
typelabel = Label(taskwin, text='Type').grid(column=0, row=2)
type_var = StringVar(value=task_types[2])
OptionMenu(taskwin, type_var, *task_types).grid(column=0, row=3, sticky='nsew')
#IMPACT
impactlabel = Label(taskwin, text='Impact').grid(column=1, row=2)
imp_var = StringVar(value=0)
OptionMenu(taskwin, imp_var, *range(0, 10+1)).grid(column=1, row=3, sticky='ns')
#MANAGEABILITY
manlabel = Label(taskwin, text='Manageability').grid(column=2, row=2)
man_var = StringVar(value=0)
OptionMenu(taskwin, man_var, *range(0, 10+1)).grid(column=2, row=3, sticky='nsew')
#PROXIMITY
proximity_label = Label(taskwin, text = 'Choose a deadline', justify='center')
proximity_label.grid(column=1, row=4)
cal = Calendar(taskwin, selectmode='day', year=2021, month=4, day=27)
cal.grid(column=1, row=5)
def get_date():
proximity_output_date.config(text=cal.get_date()) ##the .config didn't work until i did .grid(column=, row=) on seperate lines
#HOURS(required)
hourlabel = Label(taskwin, text='Whole hours \n required').grid(column=1, row=16)
hour_entry = Entry(taskwin, width=4, justify='center')
hour_entry.grid(column=1, row=17)
def add_task():
if name_entry.get() != '': # If textbox inputfield is NOT empty do this:
task_list.append(Task(name_entry.get(), type_var.get(), imp_var.get(), man_var.get(), cal.get_date(), hour_entry.get()))
show_tasks()
listbox_tasks.insert(tkinter.END, name_entry.get())
name_entry.delete(0, tkinter.END)
taskwin.destroy()
else:
tkinter.messagebox.showwarning(title='Whoops', message='You must enter a task')
next_button = Button(taskwin, text='Next', command=add_task).grid(column=2, row=18, sticky='ew')
def sort_tasks():
pass
def delete_task():
pass
#try:
#task_index = listbox_tasks.curselection()[0]
#listbox_tasks.delete(task_index)
#except:
#tkinter.messagebox.showwarning(title='Oops', message='You must select a task to delete')
def save_tasks():
pass
#tasks = listbox_tasks.get(0, listbox_tasks.size())
#pickle.dump(tasks, open('tasks.dat', 'wb'))
root = Tk()
task_frame = Frame()
# Create UI
your_tasks_label = Label(root, text='THESE ARE YOUR TASKS:', font=('Roboto',10, 'bold'), justify='center')
your_tasks_label.pack()
scrollbar_tasks = tkinter.Scrollbar(root)
scrollbar_tasks.pack(side=tkinter.RIGHT, fill=tkinter.Y)
listbox_tasks = tkinter.Listbox(root, height=10, width=50, font=('Roboto',10), justify='center') # tkinter.Listbox(where it should go, height=x, width=xx)
listbox_tasks.pack()
listbox_tasks.config(yscrollcommand=scrollbar_tasks.set)
scrollbar_tasks.config(command=listbox_tasks.yview)
try:
#tasks = pickle.load(open('tasks.dat', 'rb'))
listbox_tasks.delete(0, tkinter.END)
for task in task_list:
listbox_tasks.insert(tkinter.END, task)
except:
tkinter.messagebox.showwarning(title='Phew', message='You have no tasks')
#BUTTONS
Add_Button = Button(root, text='Add New', width=42, command=open_add_task)
Add_Button.pack()
button_delete_task = Button(root, text='Delete task', width=42, command=delete_task)
button_delete_task.pack()
button_save_tasks = Button(root, text='Save tasks', width=42, command=save_tasks)
button_save_tasks.pack()
#sort_type = StringVar(value='All')
#OptionMenu(btn_frame, sort_type, 'All', *task_types).grid(column=0, row=0, sticky='nsew')
#sort_imp = StringVar(value='Any')
#OptionMenu(btn_frame, sort_imp,'Any', *range(0, 10+1)).grid(column=1, row=0, sticky='nsew')
#Button(btn_frame, text='Sort', command=sort_tasks).grid(column=1, row=1, sticky='nsew')
root.mainloop()
Replace:
for task in task_list:
with:
task = task_list[-1]
since you want to print details for a single task and not every task in the list. You'll also want to unindent the print statement.
I am new to python and I am creating this app in python using tkinter and urllib. Basically, the program gets the URL, name, format and the path of the file then downloads it whenever the user hits the "Download" button. The problem is that without threading the program freezes until the download is finished and I don't want that to happen. So after a bit of research, I found out that threading can help solve this problem. After using threads, I found out that I can start a thread only once meaning that the user can only download one file.So I figured out that in order for the user to download multiple files and at a time, whenever the user hits the download button the program should create a new thread for that download and this even gives the user the ability to download multiple files at a time. The problem is that I have no clue how to write this algorithm. I would really appreciate it if someone helped me.
My code without threading:
from tkinter import *
from tkinter import font as tkFont
import random
import urllib.request
import requests
import wget
def printsth():
print("Yay it works! ")
def main_menu():
root = Tk()
root.title('8-bit downloader ')
root.iconbitmap(r"C:\Users\rayanravesh\PycharmProjects\GUI_Calculator\icon.ico")
root.geometry("600x300")
# the top menu
num = IntVar()
chum = IntVar()
var = IntVar()
menu = Menu(root)
root.config(menu=menu)
submenu = Menu(menu)
menu.add_cascade(label="Settings", menu=submenu)
def custom_op():
custom = Toplevel()
custom.iconbitmap(r"C:\Users\rayanravesh\PycharmProjects\GUI_Calculator\icon.ico")
submenu.add_command(label="Customization ", command=custom_op)
def settings_op():
global gps
set_win = Toplevel()
set_win.iconbitmap(r"C:\Users\rayanravesh\PycharmProjects\GUI_Calculator\icon.ico")
path_label = Label(set_win, text="Current default download path: ")
path_entry = Entry(set_win, width=30)
file_read = open('Data.txt', 'r')
data_base = file_read.read()
path_entry.insert(0, data_base)
file_read.close()
def default_output():
global location
file_read2 = open('Data.txt', 'r+')
file_read2.truncate(0)
file_read2.close()
write_file2 = open('Data.txt', 'w')
write_file2.write(path_entry.get())
write_file2.close()
location = path_entry.get() + "\\"
default_location = location.replace("\\", "\\\\")
path_btn = Button(set_win, text="Submit ", command=default_output)
path_label.pack(anchor=CENTER, expand=1)
path_entry.pack(anchor=CENTER, expand=1)
path_btn.pack(anchor=CENTER, expand=1)
submenu.add_command(label="Settings ", command=settings_op)
submenu.add_separator()
submenu.add_command(label="Exit", command=root.destroy)
# the section menu
editmenu = Menu(menu)
menu.add_cascade(label="Sections(soon)", menu=editmenu)
editmenu.add_command(label="Downloader", command=printsth)
editmenu.add_command(label="Converter", command=printsth)
editmenu.add_command(label="Media Player", command=printsth)
editmenu.add_command(label="Editor", command=printsth)
# the tool bar
toolbar = Frame(root, bg="light gray")
insert_button = Button(toolbar, text="Insert an image", command=printsth)
insert_button.pack(side=LEFT, padx=2, pady=2)
print_button = Button(toolbar, text="Print", command=printsth)
print_button.pack(side=LEFT, padx=2, pady=2)
toolbar.pack(side=TOP, fill=X)
# the download function
def download_image():
global formatname
if num.get() == 1:
name = random.randrange(1, 1000000)
else:
name = str(name_entry.get())
formatname = str(format_entry.get())
if var.get() == 1:
operator = str(url_entry.get())
formatname = '.' + operator[-3] + operator[-2] + operator[-1]
else:
pass
fullname = str(name) + formatname
url = str(url_entry.get())
fw = open('file-size.txt', 'w')
file_size = int(requests.head(url, headers={'accept-encoding': ''}).headers['Content-Length'])
fw.write(str(file_size))
fw.close()
path = str(output_entry.get()) + "\\"
if chum.get() == 1:
filee = open('Data.txt', 'r')
destination = filee.read()
path = destination + "\\"
output_entry.insert(0, destination)
filee.close()
else:
output_entry.delete(0, END)
urllib.request.urlretrieve(url, path.replace("\\", "\\\\") + fullname)
# the status bar
status_bar = Label(root, text="Downloading...", bd=1, relief=SUNKEN, anchor=W)
status_bar.pack(side=BOTTOM, fill=X)
# the download frame
body_frame = Frame(root, bg="light blue")
download_button = Button(body_frame, text="Download! ", command=download_image, border=3, width=20, height=5)
download_design = tkFont.Font(size=12, slant='italic')
download_button['font'] = download_design
download_button.pack(side=LEFT, pady=5, padx=5)
body_frame.pack(side=LEFT, fill=Y)
# the main interaction menu
inter_frame = Frame(root)
url_entry = Entry(inter_frame, width=30)
label = Label(inter_frame, text="Enter the image URL: ")
file_format = Label(inter_frame, text="Choose your file format: ")
format_entry = Entry(inter_frame, width=30)
file_name = Label(inter_frame, text="File's name: ")
name_entry = Entry(inter_frame, width=30)
check_name = Checkbutton(inter_frame, text="Give a random name", variable=num)
check_format = Checkbutton(inter_frame, text="Download with default format", variable=var)
check_default = Checkbutton(inter_frame, text="Download to default path", variable=chum)
check_default.deselect()
output_path = Label(inter_frame, text="Choose output path: ")
output_entry = Entry(inter_frame, width=30)
file_name.pack(anchor=CENTER, expand=1)
name_entry.pack(anchor=CENTER, expand=1)
check_name.pack(anchor=CENTER, expand=1)
label.pack(anchor=CENTER, expand=1)
url_entry.pack(anchor=CENTER, expand=1)
file_format.pack(anchor=CENTER, expand=1)
format_entry.pack(anchor=CENTER, expand=1)
format_entry.insert(0, '.')
check_format.pack(anchor=CENTER)
output_path.pack(anchor=CENTER, expand=1)
output_entry.pack(anchor=CENTER, expand=1)
check_default.pack(anchor=CENTER, expand=1)
inter_frame.pack(expand=1)
root.mainloop()
# the end!
main_menu()
Based on your code, you can simply change the following line in download_image() function:
urllib.request.urlretrieve(url, path.replace("\\", "\\\\") + fullname)
to:
threading.Thread(target=urllib.request.urlretrieve,
args=(url, path.replace("\\", "\\\\")+fullname), daemon=True).start()
Of course, you need to import threading.
UPDATE: to make download_image() run in thread, add a function:
def start_download():
threading.Thread(target=download_image, daemon=True).start()
and set the command option of download_button to this new function:
download_button = Button(body_frame, text="Download!",
command=start_download, border=3, width=20, height=5)
I am new to python and I am developing this simple downloader app that gets a URL form the user and downloads it to the place they specify. I want the download button to create a thread each time the user hits the button so that each thread would be responsible for one download so the user can download multiple items at a time. As a result, the program wouldn't freeze with each download but I have no idea how to do such thing. I have tried many ways but none of them seem to be working. I could really use some help.
Here is my code without threads:
from tkinter import *
from tkinter import font as tkFont
import random
import urllib.request
import requests
import wget
def printsth():
print("Yay it works! ")
def main_menu():
root = Tk()
root.title('8-bit downloader ')
root.iconbitmap(r"C:\Users\rayanravesh\PycharmProjects\GUI_Calculator\icon.ico")
root.geometry("600x300")
# the top menu
num = IntVar()
chum = IntVar()
var = IntVar()
menu = Menu(root)
root.config(menu=menu)
submenu = Menu(menu)
menu.add_cascade(label="Settings", menu=submenu)
def custom_op():
custom = Toplevel()
custom.iconbitmap(r"C:\Users\rayanravesh\PycharmProjects\GUI_Calculator\icon.ico")
submenu.add_command(label="Customization ", command=custom_op)
def settings_op():
global gps
set_win = Toplevel()
set_win.iconbitmap(r"C:\Users\rayanravesh\PycharmProjects\GUI_Calculator\icon.ico")
path_label = Label(set_win, text="Current default download path: ")
path_entry = Entry(set_win, width=30)
file_read = open('Data.txt', 'r')
data_base = file_read.read()
path_entry.insert(0, data_base)
file_read.close()
def default_output():
global location
file_read2 = open('Data.txt', 'r+')
file_read2.truncate(0)
file_read2.close()
write_file2 = open('Data.txt', 'w')
write_file2.write(path_entry.get())
write_file2.close()
location = path_entry.get() + "\\"
default_location = location.replace("\\", "\\\\")
path_btn = Button(set_win, text="Submit ", command=default_output)
path_label.pack(anchor=CENTER, expand=1)
path_entry.pack(anchor=CENTER, expand=1)
path_btn.pack(anchor=CENTER, expand=1)
submenu.add_command(label="Settings ", command=settings_op)
submenu.add_separator()
submenu.add_command(label="Exit", command=root.destroy)
# the section menu
editmenu = Menu(menu)
menu.add_cascade(label="Sections(soon)", menu=editmenu)
editmenu.add_command(label="Downloader", command=printsth)
editmenu.add_command(label="Converter", command=printsth)
editmenu.add_command(label="Media Player", command=printsth)
editmenu.add_command(label="Editor", command=printsth)
# the tool bar
toolbar = Frame(root, bg="light gray")
insert_button = Button(toolbar, text="Insert an image", command=printsth)
insert_button.pack(side=LEFT, padx=2, pady=2)
print_button = Button(toolbar, text="Print", command=printsth)
print_button.pack(side=LEFT, padx=2, pady=2)
toolbar.pack(side=TOP, fill=X)
# the download function
def download_image():
global formatname
if num.get() == 1:
name = random.randrange(1, 1000000)
else:
name = str(name_entry.get())
formatname = str(format_entry.get())
if var.get() == 1:
operator = str(url_entry.get())
formatname = '.' + operator[-3] + operator[-2] + operator[-1]
else:
pass
fullname = str(name) + formatname
url = str(url_entry.get())
fw = open('file-size.txt', 'w')
file_size = int(requests.head(url, headers={'accept-encoding': ''}).headers['Content-Length'])
fw.write(str(file_size))
fw.close()
path = str(output_entry.get()) + "\\"
if chum.get() == 1:
filee = open('Data.txt', 'r')
destination = filee.read()
path = destination + "\\"
output_entry.insert(0, destination)
filee.close()
else:
output_entry.delete(0, END)
urllib.request.urlretrieve(url, path.replace("\\", "\\\\") + fullname)
# the status bar
status_bar = Label(root, text="Downloading...", bd=1, relief=SUNKEN, anchor=W)
status_bar.pack(side=BOTTOM, fill=X)
# the download frame
body_frame = Frame(root, bg="light blue")
download_button = Button(body_frame, text="Download! ", command=download_image, border=3, width=20, height=5)
download_design = tkFont.Font(size=12, slant='italic')
download_button['font'] = download_design
download_button.pack(side=LEFT, pady=5, padx=5)
body_frame.pack(side=LEFT, fill=Y)
# the main interaction menu
inter_frame = Frame(root)
url_entry = Entry(inter_frame, width=30)
label = Label(inter_frame, text="Enter the image URL: ")
file_format = Label(inter_frame, text="Choose your file format: ")
format_entry = Entry(inter_frame, width=30)
file_name = Label(inter_frame, text="File's name: ")
name_entry = Entry(inter_frame, width=30)
check_name = Checkbutton(inter_frame, text="Give a random name", variable=num)
check_format = Checkbutton(inter_frame, text="Download with default format", variable=var)
check_default = Checkbutton(inter_frame, text="Download to default path", variable=chum)
check_default.deselect()
output_path = Label(inter_frame, text="Choose output path: ")
output_entry = Entry(inter_frame, width=30)
file_name.pack(anchor=CENTER, expand=1)
name_entry.pack(anchor=CENTER, expand=1)
check_name.pack(anchor=CENTER, expand=1)
label.pack(anchor=CENTER, expand=1)
url_entry.pack(anchor=CENTER, expand=1)
file_format.pack(anchor=CENTER, expand=1)
format_entry.pack(anchor=CENTER, expand=1)
format_entry.insert(0, '.')
check_format.pack(anchor=CENTER)
output_path.pack(anchor=CENTER, expand=1)
output_entry.pack(anchor=CENTER, expand=1)
check_default.pack(anchor=CENTER, expand=1)
inter_frame.pack(expand=1)
root.mainloop()
# the end!
main_menu()
Here is a code snippet that I used for something similar in combination with Tk:
import threading
def join_thread(thread):
thread.join(0)
if thread.is_alive():
# the thread has not finished yet -> handle it (e.g. check again after
# a certain time)
pass
def start_threaded(root, timeout):
thread = threading.Thread(
target= ..., # put your downloading function here
args=... # put your arguments here, e.g.: (URL, targetPath)
)
thread.start()
root.after(timeout, join_thread, thread)
Bind start_threaded to the according button and pass the following parameters: the root of your Tk application (we need it for checking if the thread has finished with root.after) and a timeout value in milliseconds after which we will check if the download has finished.
Note that I am not sure if Tk is thread-safe. So I would not access any widgets directly from the download threads but pass every information that is needed as an argument when creating the thread.
I am an amateur in python and I am creating this downloader app using tkinter and urllib.request and I have built the program without any threads and when I downloaded a file it would freeze until the file was downloaded and I didn't want that so I tried threading and events and it seems like it is working perfectly fine but when I want to download a second file it is not working. Why does this happen? What have I done wrong? My code:
from tkinter import *
from tkinter import font as tkFont
import random
import urllib.request
import requests
import threading
import wget
import queue
def printsth():
print("Yay it works! ")
def main_menu():
root = Tk()
root.title('8-bit downloader ')
root.iconbitmap(r"C:\Users\rayanravesh\PycharmProjects\GUI_Calculator\icon.ico")
root.geometry("600x300")
# the top menu
global num, chum, var
num = IntVar()
chum = IntVar()
var = IntVar()
menu = Menu(root)
root.config(menu=menu)
submenu = Menu(menu)
menu.add_cascade(label="Settings", menu=submenu)
def custom_op():
custom = Toplevel()
custom.iconbitmap(r"C:\Users\rayanravesh\PycharmProjects\GUI_Calculator\icon.ico")
submenu.add_command(label="Customization ", command=custom_op)
def settings_op():
global gps
set_win = Toplevel()
set_win.iconbitmap(r"C:\Users\rayanravesh\PycharmProjects\GUI_Calculator\icon.ico")
path_label = Label(set_win, text="Current default download path: ")
path_entry = Entry(set_win, width=30)
file_read = open('Data.txt', 'r')
data_base = file_read.read()
path_entry.insert(0, data_base)
file_read.close()
def default_output():
global location
file_read2 = open('Data.txt', 'r+')
file_read2.truncate(0)
file_read2.close()
write_file2 = open('Data.txt', 'w')
write_file2.write(path_entry.get())
write_file2.close()
location = path_entry.get() + "\\"
default_location = location.replace("\\", "\\\\")
path_btn = Button(set_win, text="Submit ", command=default_output)
path_label.pack(anchor=CENTER, expand=1)
path_entry.pack(anchor=CENTER, expand=1)
path_btn.pack(anchor=CENTER, expand=1)
submenu.add_command(label="Settings ", command=settings_op)
submenu.add_separator()
submenu.add_command(label="Exit", command=root.destroy)
# the section menu
editmenu = Menu(menu)
menu.add_cascade(label="Sections(soon)", menu=editmenu)
editmenu.add_command(label="Downloader", command=printsth)
editmenu.add_command(label="Converter", command=printsth)
editmenu.add_command(label="Media Player", command=printsth)
editmenu.add_command(label="Editor", command=printsth)
# the tool bar
toolbar = Frame(root, bg="light gray")
insert_button = Button(toolbar, text="Insert an image", command=printsth)
insert_button.pack(side=LEFT, padx=2, pady=2)
print_button = Button(toolbar, text="Print", command=printsth)
print_button.pack(side=LEFT, padx=2, pady=2)
toolbar.pack(side=TOP, fill=X)
# the download initiation
def initiate():
event.set()
# the status bar
status_bar = Label(root, text="Downloading...", bd=1, relief=SUNKEN, anchor=W)
status_bar.pack(side=BOTTOM, fill=X)
# the download frame
body_frame = Frame(root, bg="light blue")
download_button = Button(body_frame, text="Download! ", command=initiate, border=3, width=20, height=5)
download_design = tkFont.Font(size=12, slant='italic')
download_button['font'] = download_design
download_button.pack(side=LEFT, pady=5, padx=5)
body_frame.pack(side=LEFT, fill=Y)
# the main interaction menu
inter_frame = Frame(root)
global name_entry, format_entry, url_entry, output_entry
url_entry = Entry(inter_frame, width=30)
label = Label(inter_frame, text="Enter the image URL: ")
file_format = Label(inter_frame, text="Choose your file format: ")
format_entry = Entry(inter_frame, width=30)
file_name = Label(inter_frame, text="File's name: ")
name_entry = Entry(inter_frame, width=30)
check_name = Checkbutton(inter_frame, text="Give a random name", variable=num)
check_format = Checkbutton(inter_frame, text="Download with default format", variable=var)
check_default = Checkbutton(inter_frame, text="Download to default path", variable=chum)
check_default.deselect()
output_path = Label(inter_frame, text="Choose output path: ")
output_entry = Entry(inter_frame, width=30)
file_name.pack(anchor=CENTER, expand=1)
name_entry.pack(anchor=CENTER, expand=1)
check_name.pack(anchor=CENTER, expand=1)
label.pack(anchor=CENTER, expand=1)
url_entry.pack(anchor=CENTER, expand=1)
file_format.pack(anchor=CENTER, expand=1)
format_entry.pack(anchor=CENTER, expand=1)
format_entry.insert(0, '.')
check_format.pack(anchor=CENTER)
output_path.pack(anchor=CENTER, expand=1)
output_entry.pack(anchor=CENTER, expand=1)
check_default.pack(anchor=CENTER, expand=1)
inter_frame.pack(expand=1)
root.mainloop()
# the end!
def download_image():
event.wait()
while event.is_set():
print('hi')
global formatname
if num.get() == 1:
name = random.randrange(1, 1000000)
else:
name = str(name_entry.get())
formatname = str(format_entry.get())
'''if var.get() == 1:
operator = str(url_entry.get())
formatname = '.' + operator[-3] + operator[-2] + operator[-1]
else:
pass'''
fullname = str(name) + formatname
url = str(url_entry.get())
fw = open('file-size.txt', 'w')
file_size = int(requests.head(url, headers={'accept-encoding': ''}).headers['Content-Length'])
fw.write(str(file_size))
fw.close()
path = str(output_entry.get()) + "\\"
if chum.get() == 1:
filee = open('Data.txt', 'r')
destination = filee.read()
path = destination + "\\"
output_entry.insert(0, destination)
filee.close()
else:
output_entry.delete(0, END)
urllib.request.urlretrieve(url, path.replace("\\", "\\\\") + fullname)
event = threading.Event()
t1 = threading.Thread(target=main_menu)
t2 = threading.Thread(target=download_image)
t1.start()
t2.start()
an amateur here as well. But I suspect without knowing anything else about threading, that you can't use event.set() twice in a row.
I guess that at the end of your download_image() function you should call:
event.clear()
See the documentation here.
It might not be the right function, but closing or releasing the thread seems logical to me before you want to call it again. Sorry if it doesn't work.