Why am I getting an EOFError - python

I am making this program using tkinter and urllib which is supposed to be like a download manager. After I was nearly done with the program I realized that I had not defined a cancel button for the downloads. After looking into it more I found out about multiprocessing (before that I just used threading) and apparently it is a better module than threading for running functions in parallel and it also has a terminate function. However, no matter what I do I can't seem to understand this module. It is much more complicated than threading and I get absurd errors all the time. In my program I constantly get this error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\Family\AppData\Local\Programs\Python\Python38-32\lib\tkinter\__init__.py", line 1883, in __call__
return self.func(*args)
File "C:/Users/Family/PycharmProjects/8-bit Downloader/test.py", line 258, in start_download
Process(target=download_files,
File "C:\Users\Family\AppData\Local\Programs\Python\Python38-32\lib\multiprocessing\process.py", line 121, in start
self._popen = self._Popen(self)
File "C:\Users\Family\AppData\Local\Programs\Python\Python38-32\lib\multiprocessing\context.py", line 224, in _Popen
return _default_context.get_context().Process._Popen(process_obj)
File "C:\Users\Family\AppData\Local\Programs\Python\Python38-32\lib\multiprocessing\context.py", line 327, in _Popen
return Popen(process_obj)
File "C:\Users\Family\AppData\Local\Programs\Python\Python38-32\lib\multiprocessing\popen_spawn_win32.py", line 93, in __init__
reduction.dump(process_obj, to_child)
File "C:\Users\Family\AppData\Local\Programs\Python\Python38-32\lib\multiprocessing\reduction.py", line 60, in dump
ForkingPickler(file, protocol).dump(obj)
TypeError: cannot pickle '_tkinter.tkapp' object
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "C:\Users\Family\AppData\Local\Programs\Python\Python38-32\lib\multiprocessing\spawn.py", line 116, in spawn_main
exitcode = _main(fd, parent_sentinel)
File "C:\Users\Family\AppData\Local\Programs\Python\Python38-32\lib\multiprocessing\spawn.py", line 126, in _main
self = reduction.pickle.load(from_parent)
EOFError: Ran out of input
I have absolutely no idea what has caused this error and how to fix it. It seems like there is a problem with the start_download() function. My code (I know that it has some flaws and that I can make it cleaner, I just wanted to do that after finishing the fundamentals and if there are some parts that you think is irrelevant please inform me. ):
import os
import sqlite3
import time
import urllib.request
from multiprocessing import Process
from pathlib import Path
from tkinter import *
from tkinter import filedialog
from tkinter import font
from tkinter import messagebox
from tkinter import ttk
import numpy as np
import requests
import win10toast
from PIL import Image, ImageTk
files_downloading, times_clicked, dir_files = 0, 0, {}
info_window, customize = None, None
# The problem I believe is with the two functions below and the start function some of the code is related to the downloads tab
# which is irrelevant and some other were just functions that were unrelated so if you see a button without a function that
# exists or it is 'None' it is just deleted for the purpose of this question and also ignore the image variables!
def get_info(path, new_fullname, url_entry):
global times_clicked
lbl_await.pack_forget()
prg_br.pack_forget()
file_size = int(requests.head(str(url_entry.get()),
headers={'accept-encoding': ''}).headers['Content-Length']) / 1000000
print(file_size)
file_dir = Path(str(path).replace(" \ ".strip(), "/") + "/" + new_fullname)
size_eachsec = np.array([0.0, ])
my_scrollbar.pack(side=RIGHT, fill=Y)
lbl_fr = ttk.LabelFrame(second_frame, text=new_fullname, padding=5)
if len(new_fullname) > 20:
lbl_fr.config(text=new_fullname[:21] + "...")
download_prg = ttk.Progressbar(lbl_fr, orient=HORIZONTAL, length=365, mode='determinate', cursor="wait")
lbl_speed = Label(lbl_fr, text=None)
lbl_crnt_size = Label(lbl_fr, text=None)
lbl_file_size = Label(lbl_fr, text=f"File size: {round(file_size, 3)} MB")
lbl_percent = Label(lbl_fr, text="0 %")
lbl_cancel_btn = ttk.Button(lbl_fr, image=cancel_btn_icon)
lbl_see_more = Label(second_frame, text="See more", fg="grey", font=("Arial", 10))
download_prg.grid(row=0, column=0, columnspan=2)
lbl_speed.grid(row=0, column=2, padx=5)
lbl_crnt_size.grid(row=1, column=1)
lbl_file_size.grid(row=1, column=0)
lbl_percent.grid(row=1, column=2)
lbl_cancel_btn.grid(row=0, column=3, rowspan=2)
lbl_fr.grid(row=times_clicked, column=0, padx=5, pady=5)
lbl_see_more.grid(row=times_clicked, column=1, padx=3)
times_clicked += 1
start_time = time.time()
while True:
if file_dir.exists():
time.sleep(0.5)
crnt_size = file_dir.stat().st_size / 1000000
size_eachsec = np.append(size_eachsec, crnt_size)
percent = (crnt_size / file_size) * 100
crnt_speed = size_eachsec[1] - size_eachsec[0]
size_eachsec = np.delete(size_eachsec, 0)
lbl_speed.config(text=f"{round(crnt_speed, 2)} MB/s")
lbl_crnt_size.config(text=f"Downloaded: {round(crnt_size, 3)} MB")
lbl_percent.config(text=f"{round(percent, 2)} %")
download_prg["value"] = percent
# print( f"Current Size: {crnt_size}, Current speed: {crnt_speed}, File size: {file_size},
# Percentage: {percent}% " f", Progress bar: {download_prg['value']}%")
if crnt_size == file_size:
break
end_time = time.time()
time_elapsed = end_time - start_time
print(f"Start time: {start_time}, End time: {end_time}, Time took: {time_elapsed}")
download_prg.config(cursor="arrow")
lbl_speed.config(text="Completed!")
def show_info(event):
global info_window
if info_window is not None and info_window.winfo_exists():
info_window.focus_set()
lbl_see_more.config(fg="purple")
else:
lbl_see_more.config(fg="purple")
info_window = Toplevel()
info_window.resizable(0, 0)
lbl_time_took = Label(info_window, text=f"Time elapsed: {round(time_elapsed, 2)}")
lbl_avg_speed = Label(info_window, text=f"Average speed: {round(file_size / time_elapsed, 3)} MB/s")
lbl_time_took.pack(pady=20)
lbl_avg_speed.pack(pady=20)
lbl_see_more.bind("<Button-1>", show_info)
new_font = font.Font(lbl_see_more, lbl_see_more.cget("font"))
new_font.configure(size=10, underline=True)
lbl_see_more.config(font=new_font, fg="blue", cursor="hand2")
print("Download successful! ")
def download_files(status_bar, url_entry, output_entry, name_entry, format_entry, num, chum, var):
global files_downloading
files_downloading += 1
status_bar.config(text=f"Downloading {files_downloading} file(s)...")
url = str(url_entry.get())
if num.get() == 1:
name = url.split("/")[-1].split(".")[0]
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
static_fullname = str(name) + formatname
new_fullname = static_fullname
path = (str(output_entry.get()) + "/").replace(" \ ".strip(), "/")
if chum.get() == 1:
conn = sqlite3.connect("DEF_PATH.db")
c = conn.cursor()
c.execute("SELECT * FROM DIRECTORY_LIST WHERE SELECTED_DEF = 1")
crnt_default_path = c.fetchall()
# print(crnt_default_path)
path = str(crnt_default_path[0][0] + "/").replace(" \ ".strip(), "/")
conn.commit()
conn.close()
else:
pass
if path + static_fullname not in dir_files.keys():
dir_files[path + static_fullname] = 0
all_files_dir = os.listdir(path)
# if fullname in all_files_dir:
while new_fullname in all_files_dir:
dir_files[path + static_fullname] += 1
if num.get() == 1:
name = url.split("/")[-1].split(".")[0] + f" ({dir_files.get(path + static_fullname)})"
else:
name = str(name_entry.get()) + f" ({dir_files.get(path + static_fullname)})"
new_fullname = name + formatname
else:
pass
print(dir_files)
Process(target=get_info, args=(path, new_fullname, url_entry)).start()
urllib.request.urlretrieve(url, path + new_fullname)
if len(new_fullname) > 20:
toast.show_toast(title="8-bit Downloader",
msg=f"{new_fullname[:21] + '...'} was successfully downloaded. to '{path}'"
, duration=6, threaded=True)
else:
toast.show_toast(title="8-bit Downloader", msg=f"{new_fullname} was successfully downloaded. to '{path}'"
, duration=6, threaded=True)
files_downloading -= 1
status_bar.config(text=f"Downloading {files_downloading} file(s)...")
if files_downloading == 0:
status_bar.config(text="Download(s) successful!")
if __name__ == '__main__':
root = Tk()
tabs = ttk.Notebook()
# the top menu
num = IntVar()
chum = IntVar()
var = IntVar()
toast = win10toast.ToastNotifier()
def start_download():
Process(target=download_files,
args=(status_bar, url_entry, output_entry, name_entry, format_entry, num, chum, var),
daemon=True).start()
# the status bar
status_bar = Label(main_window, text="Awaiting download...", bd=1, relief=SUNKEN, anchor=W)
status_bar.pack(side=BOTTOM, fill=X)
# the download frame
body_frame = Frame(main_window, bg="light blue")
download_button = ttk.Button(body_frame, text="Download! ", command=start_download, padding=40, style='my.TButton')
download_button_tip = CreateToolTip(download_button, "Initiates the downloading process. ")
download_button.pack(side=LEFT, pady=5, padx=5)
body_frame.pack(side=LEFT, fill=Y)
def clear_entry(entryname, variable=None):
if variable is not None:
variable.set(0)
entryname.config(state=NORMAL)
entryname.delete(0, END)
if entryname is format_entry:
entryname.insert(0, '.')
# the main interaction menu
inter_frame = Frame(main_window)
trash_icon = ImageTk.PhotoImage(Image.open("icons/Asset 6.png"))
settings_icon = ImageTk.PhotoImage(Image.open("icons/Settings-icon.png"))
add_icon = ImageTk.PhotoImage(Image.open("icons/Plus-icon-8.png"))
minus_icon = ImageTk.PhotoImage(Image.open("icons/Minus-icon-8.png"))
change_path_icon = ImageTk.PhotoImage(Image.open("icons/Change-icon-8.png"))
url_entry = ttk.Entry(inter_frame, width=30)
label = ttk.Label(inter_frame, text="Enter the image URL: ")
clr_url = ttk.Button(inter_frame, image=trash_icon, command=lambda: clear_entry(url_entry))
file_format = ttk.Label(inter_frame, text="Choose your file format: ")
format_entry = ttk.Entry(inter_frame, width=30)
clr_format = ttk.Button(inter_frame, image=trash_icon, command=lambda: clear_entry(format_entry, var))
file_name = ttk.Label(inter_frame, text="File's name: ")
name_entry = ttk.Entry(inter_frame, width=30)
clr_name = ttk.Button(inter_frame, image=trash_icon, command=lambda: clear_entry(name_entry, num))
check_name_manual = ttk.Radiobutton(inter_frame, text="Enter name manually", variable=num,
value=0, command=lambda: name_entry.config(state=NORMAL))
check_name_auto = ttk.Radiobutton(inter_frame, text="Download with default name", variable=num,
value=1, command=lambda: name_entry.config(state=DISABLED))
check_format_manual = ttk.Radiobutton(inter_frame, text="Enter format manually", variable=var,
value=0, command=lambda: format_entry.config(state=NORMAL))
check_format_auto = ttk.Radiobutton(inter_frame, text="Download with default format", variable=var,
value=1, command=lambda: format_entry.config(state=DISABLED))
output_path = ttk.Label(inter_frame, text="Choose output path: ")
output_entry = ttk.Entry(inter_frame, width=30)
def set_path():
directory = filedialog.askdirectory(initialdir="/Downloads", title="Choose path")
if directory:
output_entry.delete(0, END)
output_entry.insert(0, directory)
select_path_btn = ttk.Button(inter_frame, width=3, text="...", command=set_path)
select_path_btn_tip = CreateToolTip(select_path_btn, "Pops up a filedialog to change directory. ")
default_path_btn = ttk.Button(inter_frame, image=settings_icon, command=None)
check_default_manual = ttk.Radiobutton(inter_frame, text="Enter path manually", variable=chum,
value=0, command=lambda: output_entry.config(state=NORMAL))
check_default_auto = ttk.Radiobutton(inter_frame, text="Download to default path", variable=chum,
value=1, command=lambda: output_entry.config(state=DISABLED))
file_name.grid(row=0, column=0, pady=(15, 10))
name_entry.grid(row=0, column=1, pady=(15, 10))
clr_name.grid(row=0, column=2, pady=(5, 0))
check_name_manual.grid(row=1, column=0, padx=(10, 0))
check_name_auto.grid(row=1, column=1, padx=(10, 0))
label.grid(row=2, column=0, pady=10, padx=(10, 0))
url_entry.grid(row=2, column=1, pady=10, padx=(10, 0))
clr_url.grid(row=2, column=2)
file_format.grid(row=3, column=0, pady=10, padx=(10, 0))
format_entry.grid(row=3, column=1, pady=10, padx=(10, 0))
format_entry.insert(0, '.')
clr_format.grid(row=3, column=2)
check_format_manual.grid(row=4, column=0, padx=(10, 0))
check_format_auto.grid(row=4, column=1, padx=(10, 0))
output_path.grid(row=5, column=0, pady=10, padx=(10, 0))
output_entry.grid(row=5, column=1, padx=(10, 5))
select_path_btn.grid(row=5, column=2)
check_default_manual.grid(row=6, column=0, pady=(0, 10), padx=(10, 0))
check_default_auto.grid(row=6, column=1, pady=(0, 10), padx=(10, 0))
default_path_btn.grid(row=6, column=2, pady=(0, 5))
inter_frame.pack(expand=1)
main_window.pack(fill="both", expand=1)
# The Downloads tab (this part is irrelevant so I wouldn't bother checking this part out just put it there in case)
lbl_await = ttk.Label(download_fr, text="Awaiting Download...", font=("Helvetica", 24))
prg_br = ttk.Progressbar(download_fr, orient=HORIZONTAL, length=250, mode='indeterminate')
my_canvas = Canvas(download_fr)
my_scrollbar = ttk.Scrollbar(download_fr, orient=VERTICAL, command=my_canvas.yview)
my_canvas.configure(yscrollcommand=my_scrollbar.set)
lbl_await.pack(pady=(85, 8))
prg_br.pack()
prg_br.start(6)
my_canvas.pack(side=LEFT, fill=BOTH, expand=1)
download_fr.pack(fill="both", expand=1)
second_frame = Frame(my_canvas)
# Add that new frame to a window in the canvas
my_canvas.create_window(0, 0, window=second_frame, anchor='nw')
# update canvas scrollregion whenever the size of second_frame is changed
second_frame.bind('<Configure>', lambda e: my_canvas.configure(scrollregion=my_canvas.bbox('all')))
tabs.pack(fill="both")
tabs.add(main_window, text="Main Window")
tabs.add(download_fr, text="Downloads")
root.mainloop()
# the end!

I think your main problem is this:
TypeError: cannot pickle '_tkinter.tkapp' object
It looks like you are trying to pass Tk objects between the processes. I doubt that will ever work.

Related

tkinter - Printing current input + by mistake also previous inputs

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.

How to create a new thread each time the user hits the download button

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)

How to initiate different and multiple threads with clicking a button in tkinter python?

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.

Why is the thread not working the second time?

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.

Tkinter/class variable/method/widget.get() from another class issue in python 2.7

I am attempting to write a python program that utilizes Tkinter window switching OOP classes. On the starting page, there is an entry form where the user fills in the relevant fields. After filling the form the button 'to tests' is clicked where the user can select the test after switching frame/window, and the user information entered is simultaneously saved in the specified directory as a .txt file as a result of this button running several methods in class Startpage. The problem occurs when data is received by clicking on the yes or no buttons in the test 1 page.
This page operates in a different class, yet requires a return value from method get_info() defined in the Startpage class to get the user information (filename) entered to create a second .txt file to store raw data, storing appended 'yes' or 'no' strings depending on the button clicked in test 1's GUI window.
However this file is never created since Test1 is not receiving any entry data from Startpage class/window, therefore cannot assign a filename (call the get_info() containing the widget.get() functions) for the second .txt file.
The information is obtained in by the methods in the class correctly and everything works fine. However the problem arises when Test1 asks to receive the widget.get() variables/methods from Startpage.
The error thrown is the following IndexError:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\Rylan\Anaconda\lib\lib-tk\Tkinter.py", line 1532, in __call__
return self.func(*args)
File "C:/Users/Rylan/Documents/Python/Basel Summerintern files/code to help with question.py", line 280, in update_countyes
directory = "C:\Users\Rylan\Documents\Python\Basel Summerintern files\{}".format(self.get_t_info())
File "C:/Users/Rylan/Documents/Python/Basel Summerintern files/code to help with question.py", line 304, in get_t_info
self.gettheinfo = Startpage(app, self.controller).get_info()
File "C:/Users/Rylan/Documents/Python/Basel Summerintern files/code to help with question.py", line 170, in get_info
str(Day) + "_" + str(Month) + "_" +
IndexError: string index out of range
I am very new to OOP programming and to my knowledge this could be caused by:
Not properly referring/calling the Startpage instance, therefore the variables are not received by the Test1, therefore calling the get_info() method results in with nothing received by the nested widget.get() functions/variables in get_info() method.
Basically, what is the reason for this IndexError and how do I fix it to get the filename created/returned from the get_info() method in class Startpage sent to/called by class Test1?
I have seen similar questions relating to class variable and method calling from a different class, however none of which consider the case for window/frame switching Tkinter applications.
Here is the simplified code below (might not seem like it) which is able to be run (you may have directory path existence issues, just change path to whatever can be easily located for you to save the .txt files)
import Tkinter as tk
import ttk
import os
LARGE_FONT = ("Verdana", 12)
NORM_FONT = ("Verdana", 10)
SMALL_FONT = ("Verdana", 8)
def center(win):
"""
centers a tkinter window
param win: the window to center on the screen
"""
win.update_idletasks()
width = win.winfo_width()
frm_width = win.winfo_rootx() - win.winfo_x()
win_width = width + 2 * frm_width
height = win.winfo_height()
titlebar_height = win.winfo_rooty() - win.winfo_y()
win_height = height + titlebar_height + frm_width
x = win.winfo_screenwidth() // 2 - win_width // 2
y = win.winfo_screenheight() // 2 - win_height // 2
win.geometry('{}x{}+{}+{}'.format(width, height, x, y))
win.deiconify()
def popupmsg(msg):
popup1 = tk.Tk()
center(popup1)
popup1.minsize(width=60, height=70)
popup1.maxsize(width=60, height=70)
popup1.wm_title("Attention!")
label = ttk.Label(popup1, text=msg, font=NORM_FONT, anchor="center")
label.pack(side="top", fill="x", pady=10)
b1 = ttk.Button(popup1, text="Ok", command=lambda: popup1.destroy())
b1.pack()
popup1.mainloop()
class Testapp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.iconbitmap(self, default="testappicon2.ico")
tk.Tk.wm_title(self, "Psychoacoustic Tests")
container = ttk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_columnconfigure(0, weight=1)
container.grid_rowconfigure(0, weight=1)
menubar = tk.Menu(container)
filemenu = tk.Menu(menubar, tearoff=0)
filemenu.add_separator()
filemenu.add_command(label="Exit", command=lambda: self.destroy())
menubar.add_cascade(label="File", menu=filemenu)
tk.Tk.config(self, menu=menubar)
self.frames = {}
for F in (Startpage, TestSelect, Test1):
frame = F(container, self)
self.frames[F] = frame
self.minsize(width=900, height=500)
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(Startpage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class Startpage(ttk.Frame):
def __init__(self, parent, controller):
ttk.Frame.__init__(self, parent)
self.controller = controller
self.titlelabel = ttk.Label(self, text="User Information", font = LARGE_FONT)
self.titlelabel.grid(row=0, column=0, columnspan=4, padx = 10, pady = 10)
self.firstnamelabel = ttk.Label(self, text="First Name: ", font = NORM_FONT)
self.firstnamelabel.grid(row=1, column=0, sticky = 'w', padx = 15, pady = 10)
self.lastnamelabel = ttk.Label(self, text="Last Name: ", font = NORM_FONT)
self.lastnamelabel.grid(row=2, column=0, sticky = 'w', padx = 15, pady = 10)
self.firstnameentry = ttk.Entry(self)
self.firstnameentry.grid(row=1, column=1, padx=5, sticky = 'we', columnspan = 3)
self.lastnameentry = ttk.Entry(self)
self.lastnameentry.grid(row=2, column=1, padx=5, sticky = 'we', columnspan = 3)
self.birthdaylabel = ttk.Label(self, text="Birthday: ", font = NORM_FONT)
self.birthdaylabel.grid(row=3, column=0, sticky = 'w', padx = 15, pady = 10)
self.daydropdown = ttk.Combobox(self, justify='center', height=20, width=2,
values = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,
15,16,17,18,19,20,21,22,23,24,25,
26,27,28,29,30,31),
state='readonly')
self.daydropdown.grid(row=3, column=1, padx = 3, sticky = 'ew')
self.monthdropdown = ttk.Combobox(self, justify='center', height=12, width=10,
values = ('January','Feburary','March',
'April','May','June','July',
'August','September','October',
'November','December'),
state='readonly')
self.monthdropdown.grid(row=3, column=2, padx=3, sticky = 'ew')
self.yeardropdown = ttk.Combobox(self, justify='center', height=20, width=4,
values = (1980, 1981, 1982, 1983, 1984,
1985, 1986, 1987, 1988, 1989,
1990, 1991, 1992, 1993, 1994,
1995, 1996, 1997, 1998, 1999),
state = 'readonly')
self.yeardropdown.grid(row=3, column=3, padx = 3, sticky = 'ew')
self.genderlabel = ttk.Label(self, text="Gender: ", font = NORM_FONT)
self.genderlabel.grid(row=4, column=0, sticky = 'w', padx = 15, pady = 10)
self.var = tk.IntVar()
self.Maleradio = ttk.Radiobutton(self, text='Male', variable=self.var, value = 1)
self.Maleradio.grid(row=4, column=1, sticky = 'w')
self.Femaleradio = ttk.Radiobutton(self, text='Female', variable=self.var, value = 2)
self.Femaleradio.grid(row=5, column=1, sticky = 'w')
self.emaillabel = ttk.Label(self, text="Email: ", font = NORM_FONT)
self.emaillabel.grid(row=6, column=0, sticky = 'w', padx = 15, pady = 10)
self.emailentry = ttk.Entry(self)
self.emailentry.grid(row=6, column=1, columnspan=3, sticky='ew')
self.experiencelabel = ttk.Label(self, text="Musical Experience: ", font = NORM_FONT)
self.experiencelabel.grid(row=7, column=0, sticky = 'w', padx = 15, pady = 10)
self.expdropdown = ttk.Combobox(self, justify='center', height=3, width=17,
values = ('No experience', 'Some experience',
'Musician level'), state='readonly')
self.expdropdown.grid(row=7, column=1, columnspan=3, sticky = 'w')
self.button1 = ttk.Button(self, text="To Tests", command= lambda: self.checkempty())
self.button1.grid(row=8, column=3)
def shortcut():
controller.show_frame(TestSelect)
buttonshort = ttk.Button(self, text="To Tests shortcut", command= lambda: shortcut())
buttonshort.grid(row=9, column=3)
def get_info(self):
Name = self.firstnameentry.get()
Surname = self.lastnameentry.get()
Day = self.daydropdown.get()
Month = self.monthdropdown.get()
Year = self.yeardropdown.get()
foldername = (str(Name[0]) + str(Surname[0]) +
str(Day) + "_" + str(Month) + "_" +
str(Year))
return foldername
def create_directory(self):
if not os.path.isdir(self.get_info()):
directory = "C:\Users\Rylan\Documents\Python\Basel Summerintern files\{}".format(self.get_info())
os.makedirs(directory)
datafile = "{}_userinfo.txt".format(self.get_info())
entirefile = os.path.join(directory, datafile)
myfile = open(entirefile, 'w')
myfile.write(self.userinfo())
myfile.close()
self.controller.show_frame(TestSelect)
else:
popupmsg("Folder already exists")
def userinfo(self):
Name = self.firstnameentry.get()
Surname = self.lastnameentry.get()
Day = self.daydropdown.get()
Month = self.monthdropdown.get()
Year = self.yeardropdown.get()
Email = self.emailentry.get()
Experience = self.expdropdown.get()
def genderget():
Gender = self.var.get()
if Gender == 1:
UserGender = "Male"
elif Gender == 2:
UserGender = "Female"
return UserGender
user_info = ("Participant Name: " + str(Name) + " " +
str(Surname) + "\nBirthday: " + str(Day) + "_" +
str(Month) + "_" + str(Year) + "\nGender: " +
str(genderget()) + "\nEmail: " + str(Email) +
"\nMusical Experience: " + str(Experience) +
"\nDirectory Name: " + str(self.get_info()))
return user_info
def checkempty(self):
Name = self.firstnameentry.get()
Surname = self.lastnameentry.get()
Day = self.daydropdown.get()
Month = self.monthdropdown.get()
Year = self.yeardropdown.get()
Email = self.emailentry.get()
Experience = self.expdropdown.get()
if len(Name) == 0:
popupmsg("Please complete the user information form")
elif len(Surname) == 0:
popupmsg("Please complete the user information form")
elif Day == None:
popupmsg("Please complete the user information form")
elif Month == None:
popupmsg("Please complete the user information form")
elif Year == None:
popupmsg("Please complete the user information form")
elif self.var.get() == 0:
popupmsg("Please complete the user information form")
elif len(Email) == 0:
popupmsg("Please complete the user information form")
elif Experience == None:
popupmsg("Please complete the user information form")
else:
self.create_directory()
class TestSelect(ttk.Frame):
def __init__(self, parent, controller):
ttk.Frame.__init__(self, parent)
self.controller = controller
label = ttk.Label(self, text="Select tests", font = LARGE_FONT)
label.grid(row=0, column=0, columnspan=3)
Test1Button = ttk.Button(self, text="Do test 1", command=lambda: controller.show_frame(Test1))
Test1Button.grid(row=1, column=0, padx = 20, pady = 15, sticky = 'nsew')
button2 = ttk.Button(self, text="Home", command=lambda: controller.show_frame(Startpage))
button2.grid(row=3, column=2)
class Test1(ttk.Frame):
def __init__(self, parent, controller):
ttk.Frame.__init__(self, parent)
self.controller = controller
label = ttk.Label(self, text="Test 1", font = LARGE_FONT)
label.grid(row=0, column=0, columnspan=2)
button2 = ttk.Button(self, text="Page one", command=lambda: controller.show_frame(TestSelect))
button2.grid(row=1, column=0, sticky = "w")
yesbutt1 = ttk.Button(self)
yesbutt1.grid(row=2, column=0)
nobutt1 = ttk.Button(self)
nobutt1.grid(row=2, column=1)
yesbutt1['text'] = "Yes: 0"
nobutt1['text'] = "No: 0"
self.nobttn_clicks = 0
self.yesbttn_clicks = 0
def update_countyes():
if self.yesbttn_clicks >= 1 or self.nobttn_clicks >= 1:
popupmsg("Only one answer allowed!")
else:
self.yesbttn_clicks += 1
yesbutt1['text'] = "Yes: " + str(self.yesbttn_clicks)
directory = "C:\Users\Rylan\Documents\Python\Basel Summerintern files\{}".format(self.get_t_info())
datafile = "{}_test1data.txt".format(self.get_t_info())
entirefile = os.path.join(directory, datafile)
myfile = open(entirefile, 'a')
myfile.write('\nyes')
myfile.close()
def update_countno():
if self.yesbttn_clicks >= 1 or self.nobttn_clicks >= 1:
popupmsg("Only one answer allowed!")
else:
self.nobttn_clicks += 1
nobutt1['text'] = "No: " + str(self.nobttn_clicks)
directory = "C:\Users\Rylan\Documents\Python\Basel Summerintern files\{}".format(self.get_t_info())
datafile = "{}_test1data.txt".format(self.get_t_info())
entirefile = os.path.join(directory, datafile)
myfile = open(entirefile, 'a')
myfile.write('\nno')
myfile.close()
yesbutt1['command'] = update_countyes
nobutt1['command'] = update_countno
def get_t_info(self):
self.gettheinfo = Startpage(app, self.controller).get_info()
return self.gettheinfo
app = Testapp()
app.mainloop()
Your problem is that when you write:
def get_t_info(self):
self.gettheinfo = Startpage(app, self.controller).get_info()
return self.gettheinfo
you create a new StartPage where the Entries are empty.
Then
Name = self.firstnameentry.get()
...
foldername = (str(Name[0])
tries to get the first character of an empty string.
I think the solution should be something like:
def get_t_info(self):
return self.controller.frames[Startpage]

Categories

Resources