How to thread a application? - python

I'll be referring to python in this question.
Ok, let's say i have a script that renames 1000 files.How do i multithread it?
I thought about dividing the files into chunks but it makes the code too complex, and to run 1000 thread, one for each file, isn't going to work.
Here is the code.
import os
import tkinter.messagebox
import tkinter.ttk
import tkinter.filedialog
from tkinter import Tk, StringVar, Text, END
print("""
A little reminder!
Any file that gets renamed can't be undo,so don't screw around with this.
NOTE : Careful with the extension,you might lose some files this way.
""")
class Rename:
def __init__(self,path): self.p = path
def rename(self):
try:
files = os.listdir(self.p)
i = 0
os.chdir(self.p)
while i <= len(files):
ext = files[i].split(".")[-1]
#You can change the renaming variable,for example you may add "file{}.{}".format(i,ext)..
#also,don't play with the ext if you don't know what you're doing..
os.rename(files[i],"{}.{}".format(i,ext))
i += 1
yield "Now renaming {}".format(files[i])
except OSError as e: print("Error -> {}".format(e))
except IndexError: pass
class GUI:
def __init__(self):
self.root = Tk()
self.root.wm_title("FileRenamer")
self.root.config(background = "black")
# Label
self.label = tkinter.ttk.Label(self.root, text = "Path: ")
self.label.config(foreground = "white", background = "black", font = ("Arial", 16))
self.label.grid(row = 0, column = 0)
# File dialog
self.path = StringVar()
self.filepath = tkinter.ttk.Button(self.root, text = "Choose", command = self.askPath).grid(row = 0, column = 1)
# TextWidget
self.text = Text(self.root, height = 5, width = 50)
self.text.config(foreground = "white", background = "black", font = ("Arial", 12))
self.text.grid(row = 3, column = 0, columnspan = 2)
# Button
self.button = tkinter.ttk.Button(self.root, text = "Rename", command = self.rename)
self.button.grid(row = 2, column = 1, columnspan = 2)
self.root.mainloop()
def askPath(self):
self.path = tkinter.filedialog.askdirectory()
def rename(self):
path = os.path.abspath(self.path)
rem = Rename(path)
for im in rem.rename():
self.text.insert(END, "{}\n".format(im))
# Make sure that you add another "\" to the path you enter, otherwise you'll get an error.
r = GUI()

Related

is there a way to grid an extra button while running your program in tkinter correctly?

I'm making an mp3 player app and I want the user to be able to add playlists (which will be buttons in a grid system.
Like so.
However in this state when I'm trying to add a playlist button this happens:
The top buttons and the button i just added get squeezed off and the scrollbar is stuck (I can't use it)
I've tried refreshing by self.playlist_frame.update_idletasks() after running create_playlists() but it doesn't seem to change anything
this is my code so you can test it:
import os
import tkinter as tk
from tkinter import ttk
from PIL import Image, ImageTk
class MyApp:
def __init__(self):
self.root = tk.Tk()
self.width = self.root.winfo_screenwidth()
self.height = self.root.winfo_screenheight()
self.height = self.root.winfo_screenheight() - int(self.height / 13)
self.root.geometry(f'{self.width}x{self.height}')
self.root.title("Mp3")
self.c = '#14141D'
self.playlists_buttons_list = []
self.playlists = {}
self.helping_d = {}
self.main = ttk.Notebook(self.root)
self.playlists_tab = tk.Frame(self.main)
self.playlist_menu_frame = tk.Frame(self.playlists_tab, bg=self.c)
self.playlists_canvas = tk.Canvas(self.playlists_tab, bg=self.c)
self.playlist_frame = tk.Frame(self.playlists_canvas, bg=self.c)
self.playlists_scrollbar = ttk.Scrollbar(self.playlists_tab, orient='vertical',
command=self.playlists_canvas.yview)
self.add_playlist_win = tk.Toplevel(self.root)
self.add_playlists_button = tk.Button(self.playlist_frame)
self.default_img = Image.open('images/default.png').resize((75, 72))
self.default_img = ImageTk.PhotoImage(self.default_img)
self.add_img = Image.open('images/add.png').resize((50, 50))
self.add_img = ImageTk.PhotoImage(self.add_img)
self.widgets()
self.root.mainloop()
def widgets(self):
self.playlists_tab.place(height=self.height, width=self.width, x=0, y=0)
self.main.add(self.playlists_tab, text="Playlists")
self.main.pack(expand=1, fill="both")
self.playlist_frame = tk.Frame(self.playlists_canvas, bg=self.c)
self.playlists_canvas.create_window((0, 0), window=self.playlist_frame, anchor='center')
self.playlists_canvas.config(bg=self.c)
self.playlists_canvas.place(height=int(self.height / 1.428), width=self.width, x=0, y=int(self.height / 9))
self.add_playlists_button = tk.Button(self.playlists_canvas, image=self.add_img, bg=self.c, bd=0,
command=self.add_playlists)
self.add_playlists_button.place(x=1284, y=75)
self.playlists_scrollbar.pack(side='right', fill='y')
self.playlists_canvas.config(yscrollcommand=self.playlists_scrollbar.set)
self.playlists_canvas.bind('<Configure>', lambda e: self.playlists_canvas.configure(
scrollregion=self.playlists_canvas.bbox('all')))
if os.path.getsize('playlistsnames.txt') != 0:
lines = open('playlistsnames.txt', 'r', encoding='utf-8').read().splitlines()
for i in lines:
self.playlists[i] = []
self.create_playlists()
def create_playlists(self):
self.playlists_buttons_list = []
for i in range(len(self.playlists.keys())):
self.playlists_buttons_list.append(tk.Button(self.playlist_frame, bg=self.c,
text=' ' + list(self.playlists.keys())[i].split('!')[0],
fg='white', image=self.default_img, height=280, width=300))
row = 0
column = 0
for i in self.playlists_buttons_list:
if column > 3:
row += 1
column = 0
if column > 7:
row += 1
column = 0
i.grid(row=row, column=column)
column += 1
def get_name(self):
self.name_of_plst = self.plst_entry.get()
self.playlists[self.name_of_plst] = []
self.create_playlists()
with open('playlistsnames.txt', 'a', encoding='utf-8') as names_file:
names_file.write(self.name_of_plst + '!\n')
def add_playlists(self):
self.add_playlist_win = tk.Toplevel(self.root)
self.name_label = tk.Label(self.add_playlist_win, text='Name:', bg=self.c, fg='pink').pack()
self.plst_entry = tk.Entry(self.add_playlist_win)
self.plst_entry.pack()
self.confirm_btn = tk.Button(self.add_playlist_win, text='Confirm', bg=self.c, fg='pink',
command=self.get_name).pack()
self.add_playlist_win.mainloop()
MyApp()
I should also mention that because I store the playlist names in a file called playlistnames.txt when I rerun the program I can see all the playlist buttons plus the one I created before and things work just fine.
So what I want is making the grid update and work while running the app without having to rerun the app of course
My playlistsnames.txt file has this format:
rock!
metal!
chill!
rap!
jazz!
blues!
hard rock!
trap!
Any suggestions would be helpful!
Thanks in advance!

Tkinter: function starts when running tkinter code

I have searched for similar questions but I can't seem to figure out what i am doing wrong. I have this code for a very simple gui. The code in googl1 is a scraper that extracts information from google. But I have this problem where when I run the code for the gui, the scraper starts before the gui is shown.
Could someone explain why this is?
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog, messagebox
from functools import partial
HEIGHT = 500
WIDTH = 600
import google1
#----Functions----------------------------------------------------------------
def fileDialog():
global filename
filename = filedialog.askopenfilename(initialdir = "/",title = "Select file",filetypes = (("excel workbook","*.xlsx"),("all files","*.*")))
label = ttk.Label(labelFrame, text = "")
label.grid(column = 1, row = 4)
label.configure(text = filename)
print(filename)
def start_program(filename):
if filename:
print("this is the filename", filename)
google1.start_program
else:
messagebox(title="No file detected", message="Please select file first")
#----Tkinter-setup------------------------------------------------------------
root = tk.Tk()
#initial placeholder for gui
canvas = tk.Canvas(root, height=HEIGHT, width=WIDTH)
canvas.pack()
#a frame within the canvas
frame = tk.Frame(root, bg='#80c1ff')
frame.place(relx=0.1, rely=0.1, relwidth=0.8, relheight=0.8)
labelFrame = tk.LabelFrame(frame, text = "Select File")
labelFrame.grid(column = 0, row = 1, padx = 20, pady = 20)
labelFrame_start = tk.LabelFrame(frame, text = "Start Program")
labelFrame_start.grid(column = 0, row = 3, padx = 20, pady = 20)
button = tk.Button(labelFrame, text = "Browse Files", command = fileDialog)
button.grid(column = 1, row = 1)
button = tk.Button(labelFrame_start, text = "Click to start program", command = lambda: start_program(filename))
button.grid(column = 1, row = 1)
root.mainloop()
edit: this (the scraper starting before seeing the gui) also happens when I comment out the google1.start_program, but still have the import. When I also comment out the import, that is when i do get the gui first.

Apply two or more commands at the same time in python

I created a simple program to convert video to audio, using the moviepy library and the program as follows:
import moviepy.editor as mp
from tkinter import *
from tkinter import ttk
from tkinter.filedialog import asksaveasfile, askopenfile
from tkinter.messagebox import showerror
def Open():
video_path = askopenfile(initialdir = "Video", title = "Open Video", filetypes = (("Video", "*.MP4;*.AVI;*.WAV;*.MKV;*.webm;*.TS;*.ASF;*OOG"), ("All files", "*.*")))
try:
open(video_path.name, "r")
ent_mp4.delete(0, END)
ent_mp4.insert(0, video_path.name)
except:
pass
def save_in():
if not(ent_mp4.get() == ""):
saveas = asksaveasfile(initialdir = "Music", title = "Save in", filetype = [("Aduio", "*.MP3;*.FLAC;*.CD;*.WMV"), ("All filest", "*.*")])
ent_mp3.delete(0, END)
ent_mp3.insert(0, saveas.name)
else:
showerror("Error: Empty Entry", "Pleas Enter Your Video Path")
def convert():
video = ent_mp4.get()
music = ent_mp3.get()
if not(music == ""):
root.destroy()
clip = mp.VideoFileClip(video)
clip.audio.write_audiofile(music)
main()
else:
showerror("Error: Empty Entry", "Pleas Enter Your Music Path")
ent_mp4, ent_mp3, root = None, None, None
bu1, bu2, bu3 = None, None, None
def main():
global ent_mp3, ent_mp4, root, bu1, bu2, bu3, sv
root = Tk()
root.title("Convert Video to Audio")
ent_mp4 = ttk.Entry(root, width = 50)
ent_mp4.grid(row = 0, column = 0)
ent_mp3 = ttk.Entry(root, width = 50)
ent_mp3.grid(row = 1, column = 0)
ttk.Button(root, text = "Open video", command = lambda: Open()).grid(row = 0, column = 1)
ttk.Button(root, text = "Save in", command = lambda: save_in()).grid(row = 1, column = 1)
f = ttk.Frame(root)
f.grid(row = 2, column = 0, columnspan = 2)
ttk.Button(f, text = "Convert", command = lambda: convert()).pack(side = LEFT)
ttk.Button(f, text = "Exit", command = lambda: exit()).pack(side = RIGHT)
root.mainloop()
main()
The program is successful but I just want to add something simple, which is that instead of removing the window when the root.destroy () switching process is running, an animated GIF is added that indicates that the process is in progress
I suspect that the solution is to apply two things at the same time for the process to succeed
But I didn't find how to try the "with" command but it didn't work out
So what is the solution
Threading will alow two or more functions to run simultaneously.
from threading import Thread
def func1():
print('Working')
def func2():
print('Working')
if __name__ == '__main__':
Thread(target = func1).start()
Thread(target = func2).start()

Running into problems with class inheritance an tkinter listBox insert

I am currently trying to make a simple Jukebox/Music Player in Python and ran into some concerns with class inheritance and tkinter's listBox method.
I have to two classes JukeboxGUI and JukeboxContent (the content one is incomplete). The JukeboxContent class inherits the JukeboxGUI:
import os
import pygame
#from PIL import Image
from tkinter.filedialog import askdirectory
from tkinter import *
import eyed3
class JukeboxGUI:
def __init__(self, window):
self.photo = PhotoImage(file = "//Users//nukhbahmajid//Desktop//Jukebox//background2.gif")
self.canvas = Canvas(width = 1000, height = 1000, bg = "black")
self.label = Label(self.canvas, text = "Jukebox")
self.listBox = Listbox(self.canvas)
self.playPauseButton = Button(self.canvas, text = "Play / Pause")
self.nextButton = Button(self.canvas, text = "Next Song")
self.previousButton = Button(self.canvas, text = "Previous Song")
self.stopButton = Button(self.canvas, text = "Stop")
self.labelVar = StringVar()
self.songLabel = Label(self.canvas, textvariable = self.labelVar, width = 20)
def constructButtons(self):
self.canvas.pack()
self.canvas.create_image(0,0, image = self.photo, anchor = NW)
self.label = self.canvas.create_window(325, 40, anchor = NW, window = self.label)
self.listBox = self.canvas.create_window(270, 80, anchor = NW, window = self.listBox)
self.playPauseButton = self.canvas.create_window(110, 120, anchor = NW, window = self.playPauseButton)
self.nextButton = self.canvas.create_window(500, 120, anchor = NW, window = self.nextButton)
self.previousButton = self.canvas.create_window(500, 180, anchor = NW, window = self.previousButton)
self.stopButton = self.canvas.create_window(130, 183, anchor = NW, window = self.stopButton)
self.songLabel = self.canvas.create_window(268, 268, anchor = NW, window = self.songLabel)
class JukeboxContent(JukeboxGUI):
def __init__(self, window):
#JukeboxGUI.__init__(self, window)
super(JukeboxContent, self).__init__(window)
listOfSongs = []
songTitles = []
num_songs = len(songTitles)
self.index = 1
self.listOfSongs = listOfSongs
self.songTitles = songTitles
self.directoryAsk = askdirectory()
self.num_songs = num_songs
self.Error_NoMP3s = "No \".mp3\" files found."
def directoryChooser(self):
self.directoryAsk
os.chdir(self.directoryAsk)
for files in os.listdir(self.directoryAsk):
if files.endswith(".mp3"):
realdir = os.path.realpath(files)
audioTag = eyed3.load(realdir)
self.songTitles.append(audioTag.tag.title)
self.listOfSongs.append(files)
print(files) ## comment out or remove later
print("These are the Song titles:", self.songTitles) #check if the list gets appended
for items in self.songTitles:
self.listBox.insert(END, items) ## the list doesn't get inserted into the listbox
pygame.mixer.init()
pygame.mixer.music.load(self.listOfSongs[0])
self.labelVar.set(self.songTitles[0])
print("The label variable:", self.labelVar) ## the variable isn't set either
print("The label is accessible:", self.songLabel) ## songLabel doesn't get updated
pygame.mixer.music.play() # the song doesn't play
if __name__ == "__main__":
window = Tk()
window.geometry("700x500+450+200")
window.title("Jukebox")
constructGUI = JukeboxGUI(window)
constructGUI.constructButtons()
initiateJukebox = JukeboxContent(window)
initiateJukebox.directoryChooser()
window.mainloop()
When I try to access the attributes of the parent class, like inserting the songs into the list box, there isn't an error here specifically, but the list isn't into the box either
Secondly, when I update the label variable and songLabel, and try to print out later to see if it was implemented, the following gets printed to the terminal:
The label variable: PY_VAR1
The label is accessible: .!canvas2.!label2
The song doesn't play either. What could be the problem? Please help me out! Here's a picture of the interface if it helps:
JukeboxInterface

How to display output of print() in GUI python

I am new in creating GUI. I am doing it in Python with Tkinter. In my program I calculate following characteristics
def my_myfunction():
my code ...
print("Centroid:", centroid_x, centroid_y)
print("Area:", area)
print("Angle:", angle)
I would like to ask for any help/tips how to display those values in GUI window or how to save them in .txt file so that I can call them in my GUI
Thanks in advance
Tkinter is easy and an easy way to do a GUI, but sometimes it can be frustrating. But you should have read the docs before.
However, you can do in this way.
from tkinter import *
yourData = "My text here"
root = Tk()
frame = Frame(root, width=100, height=100)
frame.pack()
lab = Label(frame,text=yourData)
lab.pack()
root.mainloop()
There are several ways to display the results of any operation in tkiner.
You can use Label, Entry, Text, or even pop up messages boxes. There are some other options but these will probably be what you are looking for.
Take a look at the below example.
I have a simple adding program that will take 2 numbers and add them together. It will display the results in each kind of field you can use as an output in tkinter.
import tkinter as tk
from tkinter import messagebox
class App(tk.Frame):
def __init__(self, master):
self.master = master
lbl1 = tk.Label(self.master, text = "Enter 2 numbers to be added \ntogether and click submit")
lbl1.grid(row = 0, column = 0, columnspan = 3)
self.entry1 = tk.Entry(self.master, width = 5)
self.entry1.grid(row = 1, column = 0)
self.lbl2 = tk.Label(self.master, text = "+")
self.lbl2.grid(row = 1, column = 1)
self.entry2 = tk.Entry(self.master, width = 5)
self.entry2.grid(row = 1, column = 2)
btn1 = tk.Button(self.master, text = "Submit", command = self.add_numbers)
btn1.grid(row = 2, column = 1)
self.lbl3 = tk.Label(self.master, text = "Sum = ")
self.lbl3.grid(row = 3, column = 1)
self.entry3 = tk.Entry(self.master, width = 10)
self.entry3.grid(row = 4, column = 1)
self.text1 = tk.Text(self.master, height = 1, width = 10)
self.text1.grid(row = 5, column = 1)
def add_numbers(self):
x = self.entry1.get()
y = self.entry2.get()
if x != "" and y != "":
sumxy = int(x) + int(y)
self.lbl3.config(text = "Sum = {}".format(sumxy))
self.entry3.delete(0, "end")
self.entry3.insert(0, sumxy)
self.text1.delete(1.0, "end")
self.text1.insert(1.0, sumxy)
messagebox.showinfo("Sum of {} and {}".format(x,y),
"Sum of {} and {} = {}".format(x, y, sumxy))
if __name__ == "__main__":
root = tk.Tk()
myapp = App(root)
root.mainloop()

Categories