How to call multiple buttons together in Tkinter - python

I'm trying to create a window with 3 buttons. When a user clicks on one of the buttons, the assigned function is called. Here is my code, I tried everything from what I read in the documentation, but I can't seem to get over it!
I also added the functions called by the program, they work perfectly, just adding them for reference. Also, the buttons() function is called only one time and it's a simple call without argument.
def buttons():
root.geometry('1000x1000')
btncreation = tkinter.Button(root, text='Order by Creation',
command=creation)
btncreation.pack()
btnmodified = tkinter.Button(root, text='Order by Last Modified',
command=lastmodified)
btnmodified.pack()
btnaccessed = tkinter.Button(root, text='Order by Last Accessed',
command=lastaccessed)
btnaccessed.pack()
def creation():
lst.sort(key=os.path.getctime)
num = 1
for line in lst:
dst = newpath + name + str(num) + suffix
rename(line, dst)
num += 1
def lastmodified():
lst.sort(key=os.path.getmtime)
num = 1
for line in lst:
dst = newpath + name + str(num) + suffix
rename(line, dst)
num += 1
Functions called by buttons:
def lastaccessed():
lst.sort(key=os.path.getatime)
num = 1
for line in lst:
dst = newpath + name + str(num) + suffix
rename(line, dst)
num += 1
Also, please, please, refrain from formatting answers on my question. I just want some honest to god help and not 5 comments on how to "better format my question". If you need more info, I'll be glad to give it. But I'm not answering salty comments on the formatting :)
import os
import tkinter.filedialog
import pathlib
from os import rename
from tkinter import simpledialog
import getpass
import tkinter as tk
root = tkinter.Tk()
# File types list
ftypes = [
('Python code files', '*.py'),
('Perl code files', '*.pl;*.pm'),
('Java code files', '*.java'),
('C++ code files', '*.cpp;*.h'),
('Text files on mac', '*.rtf'),
('Text files', '*.txt'),
("PDF files", "*.pdf"),
('All files', '*'),
]
# The function renames and relocates selected files depending on the sorting selected
def creation():
lst.sort(key=os.path.getctime)
num = 1
for line in lst:
dst = newpath + name + str(num) + suffix
rename(line, dst)
num += 1
def lastmodified():
lst.sort(key=os.path.getmtime)
num = 1
for line in lst:
dst = newpath + name + str(num) + suffix
rename(line, dst)
num += 1
def lastaccessed():
lst.sort(key=os.path.getatime)
num = 1
for line in lst:
dst = newpath + name + str(num) + suffix
rename(line, dst)
num += 1
def hide(root):
root.withdraw()
def show(root):
root.update()
root.deiconify()
def buttons():
root.geometry('1000x1000')
btncreation = tkinter.Button(root, text='Order by Creation',
command=creation)
btncreation.pack()
btnmodified = tkinter.Button(root, text='Order by Last Modified',
command=lastmodified)
btnmodified.pack()
btnaccessed = tkinter.Button(root, text='Order by Last Accessed',
command=lastaccessed)
btnaccessed.pack()
hide(root)
# Window to select files to order
filez = tkinter.filedialog.askopenfilenames(title='Select files to rename (must be all of the same type!)')
# List populated with file names
lst = list(filez)
# Saves the extension of the selected files
suffix = pathlib.Path(lst[0]).suffix
# Window to get user input on file naming
# Asks user for file names, while loop won't break if no name is given
USER_INP = simpledialog.askstring(title="File Names",
prompt="Name your files:")
while USER_INP == '':
USER_INP = simpledialog.askstring(title="File Names",
prompt="Name your files:")
# Gets username for path use
username = getpass.getuser()
name = USER_INP
# Asks user for folder name, while loop won't break if no name is given
USER_INP2 = simpledialog.askstring(title="Folder Name",
prompt="Name your folder:")
while USER_INP2 == '':
USER_INP2 = simpledialog.askstring(title="Folder Name",
prompt="Name your folder:")
foldername = USER_INP2
# Creates new folder for ordered files, if folder exists, it uses it
newpath = r'/Users/' + username + '/Desktop/' + foldername + '/'
if not os.path.exists(newpath):
os.makedirs(newpath)
buttons()
root.mainloop()

You can start by using hide(root) but before or after calling buttons() say, show(root), so:
# Rest of your code
hide(root)
# Rest of your code
show(root)
buttons()

Related

Why do these buttons open the same file regardless of which on I select?

I'm making a pdf 'date checker' in Python which tells me if every page of the pdf has tomorrows date at the top (for checking newspapers as part of my job).
So far so good until I attempted to put it all into a GUI, the buttons display the correct filename, but only open and check the last file in he list the buttons were generated from 'Files[i]'.
Can anybody figure out from my horrible nooby code why this is happening? please excuse the mess (I'm new) :)
Here is my ugly code :) I think the issue is either where I open the file using
'with open(files[i])' or 3rd line from the bottom where the buttons are created.
Any help would be greatly appreciated, thank you.
import os, glob
import fileinput
import tkinter as tk
import dateutil
import datetime
from dateutil.relativedelta import *
from dateutil.easter import *
from dateutil.parser import *
from dateutil.rrule import *
import PyPDF2
from PyPDF2 import PdfReader
from datetime import datetime, timedelta
from tkinter import *
folder_path = 'C:users/axlra/documents/datechecker'
for filename in glob.glob(os.path.join(folder_path, '*.pdf')):
with open(files[i], 'r') as f:
text = f.read()
print (files[i])
print (len(text))
def checknow():
tomorrow = (datetime.now() + timedelta(days=1)).strftime("%d-%m-%Y")
file = open(files[i], 'rb')
reader = PdfReader(files[i])
total = len(reader.pages)
for x in range(total+1):
if x > total: file.close()
page = reader.pages[0]
found = False
text = (page.extract_text())
parts = []
def visitor_body(text, cm, tm, fontDict, fontSize):
y = tm[5]
if y > 1600 and y < 10000:
parts.append(text)
page.extract_text(visitor_text=visitor_body)
text_body = "".join(parts)
#print(text_body)
word = text_body
word=word[22:-1]
#print(word)
prodate = parse(word)
str_date = prodate.strftime("%d-%m-%Y")
print(str_date)
print(files[i])
if tomorrow in str_date:
found = True
if found:
#print(x)
print("Tomorrow's date was found on page"+ " "+str(x))
else:
#print(x)
print("Tomorrow's date was NOT found on page"+ " "+str(x))
location = os.getcwd() # get present working directory location here
counter = 0 #keep a count of all files found
files = [] #list to store all pdf files found at location
for file in os.listdir(location):
try:
if file.endswith(".pdf"):
print ("pdf file found:\t", file)
files.append(str(file))
counter = counter
except Exception as e:
raise e
print ("No files found here!")
root = Tk()
btn = [] #creates list to store the buttons ins
for i in range(counter): #this just popultes a list as a replacement for the actual inputs for troubleshooting purposes
files.append(str(i))
for i in range(len(files)): #this says for *counter* in *however many elements there are in the list files*
#the below line creates a button and stores it in an array we can call later, it will print the value of it's own text by referencing itself from the list that the buttons are stored in
btn.append(Button(root, text=files[i], command=checknow))
btn[i].pack() #this packs the buttons
root.mainloop()
Based off the given solutions, this is the working code, the solution was to completely get rid of the 'i list' and just use file_path:
import os
import tkinter as tk
from tkinter import messagebox
import os, glob
import fileinput
import tkinter as tk
import dateutil
import datetime
from dateutil.relativedelta import *
from dateutil.easter import *
from dateutil.parser import *
from dateutil.rrule import *
import PyPDF2
from PyPDF2 import PdfReader
from datetime import datetime, timedelta
from tkinter import *
import re
location = os.getcwd()
counter = 0
files = []
for file in os.listdir(location):
try:
if file.endswith(".pdf"):
print ("pdf file found:\t", file)
files.append(str(file))
counter = counter
except Exception as e:
raise e
print ("No files found here!")
tomorrow = (datetime.now() + timedelta(days=-1)).strftime("%A,%B%e")
tomorrow = tomorrow.replace(" ", "")
tomorrow2 = (datetime.now() + timedelta(days=-1)).strftime("%d.%m.%Y")
tomorrow2 = tomorrow.replace(" ", "")
tomorrow3 = (datetime.now() + timedelta(days=-1)).strftime("%A%e%B%Y")
tomorrow3 = tomorrow.replace(" ", "")
tomorrow4 = (datetime.now() + timedelta(days=-1)).strftime("%A,%B%e")
tomorrow4 = tomorrow.replace(" ", "")
tomorrow5 = (datetime.now() + timedelta(days=-1)).strftime("%A,%e%B")
tomorrow5 = tomorrow.replace(" ", "")
def open_pdf(file_path):
file = open(file_path, 'rb')
reader = PdfReader(file)
total = len(reader.pages)
for x in range(total):
if x > x: file.close()
page = reader.pages[x]
text = (page.extract_text())
text = text.replace(" ", "")
#print(text)
substring = tomorrow
first_index = text.find(substring)
if first_index != -1:
second_index = text.find(substring, first_index + len(substring))
if second_index != -1:
print("Tomorrows date "+ tomorrow+ " appears twice on page"+ " "+str(x).format(substring))
else:
print("Tomorrows date "+ tomorrow+ " appears only once on page"+ " "+str(x)+" -".format(substring))
else:
print("Tomorrows date "+ tomorrow+ " does not appear on page"+ " "+str(x)+" ---".format(substring))
def create_buttons(directory):
for filename in os.listdir(directory):
if filename.endswith(".pdf"):
file_path = os.path.join(directory, filename)
button = tk.Button(root, text=filename, command=lambda f=file_path: open_pdf(f))
button.pack()
root = tk.Tk()
create_buttons(os.getcwd())
root.mainloop()
The basic answer is that at the end of for i in range(len(files)) the i does not get dereference like it does in some languages. A simple test to do is that this will give you an i of 2.
for i in range(3):
pass
print(i)
So when you call checknow() the referenced file would be the last file in files since your i doesn't change after the loop.
Something I've done in the past is create a class encompassing it so that each one holds to their own references. I did it without subclassing the tkinter class, but you could. A sample for an idea of what I did is
class FileButton:
def checknow(self):
file_name = self._file_name
#as an example of how you can reference the file_name.
#you can also do this by doing self._button.cget("text") and not have to store file_name
pass
def __init__(self, root, file_name):
self._root = root
self._file_name = file_name
self._button = tkinter.Button(root, text=file_name, command=self.checknow)
self._button.pack()
for i in range(len(files)):
btn.append(FileButton(root, files[i]))
I haven't tested this particular code, and my previous uses were more for labels and entries, but the principle of it was the same and I can confirm that using the callback in this manner worked. Also, if you don't need to reference the buttons anymore you don't have to append them to the btn list either.

Python expecting expected str, bytes or os.PathLike object, not StringVar

Okay, so I'm working on a project that monitors two selected folders and automatically moves files created or edited within the last twenty-four hours from Folder_A to Folder_B. It also will check the two folders manually when the user clicks the scan button. So far it will select the two folders, but when I click the scan button I get this error. How would I go about fixing the error? My code is below the error. Please be understanding that I am still really new to python, so there might be quite a few really stupid mistakes in here.
File
"C:\Users\--\AppData\Local\Programs\Python\Python310\Projects\File_transfer.py", line 63, in <module>
scan_btn=Button(text="Scan", command = submitFunction())
File "C:\Users\--\AppData\Local\Programs\Python\Python310\Projects\File_transfer.py", line 34, in submitFunction
for root, dirs,files in os.walk(origin_path):
File "C:\Users\quirk\AppData\Local\Programs\Python\Python310\lib\os.py", line 342, in walk
return _walk(fspath(top), topdown, onerror, followlinks)
TypeError: expected str, bytes or os.PathLike object, not StringVar
My code for the project:
import tkinter
import tkinter as tk
from tkinter import *
from tkinter import filedialog
import os,time
import datetime
import shutil
import datetime as dt
def browse_button():
# Allow user to select a directory and store it in global var
# called origin_path
global origin_path
filename = filedialog.askdirectory()
origin_path.set(filename)
print(filename)
def browse_button2():
# Allow user to select a directory and store it in global var
# called receiving_path
global receiving_path
filename = filedialog.askdirectory()
receiving_path.set(filename)
print(filename)
def submitFunction() :
for root, dirs,files in os.walk(origin_path):
for fname in files:
path = os.path.join(root, fname)
st = os.stat(path)
mtime = dt.datetime.fromtimestamp(st.st_mtime)
shutil.move(path, dest)
print('Submit button is clicked.')
root = Tk()
origin_path = StringVar()
receiving_path = StringVar()
#First Browse Button Label
lbl1 = Label(master=root,textvariable=origin_path)
lbl1.grid(row=0, column=1)
#Second Browse Button Label
lbl1_2 = Label(master=root,textvariable=receiving_path)
lbl1_2.grid(row=1, column=1)
lbl1_3 = Label(master=root)
lbl1_3.grid(row=2, column=1)
button = Button(text="Browse", command=browse_button)
button.grid(row=0, column=3)
button2 = Button(text="Browse", command=browse_button2)
button2.grid(row=1, column=3)
scan_btn=Button(text="Scan", command = lambda:submitFunction())
scan_btn.grid(row=2, column=7)
mainloop()
now = dt.datetime.now()
ago = now-dt.timedelta(hours=24)
strftime = "%H:%M %m/%d/%Y"
created = 'origin_path'
dest = 'receiving_path'
file_path = 'file:///'+os.getcwd()+'/' + ''
print("Last modified: %s" % time.ctime(os.path.getmtime(file_path)))
print("Created: %s" % time.ctime(os.path.getctime(file_path)))
for root, dirs,files in os.walk(origin_path):
for fname in files:
path = os.path.join(root, fname)
st = os.stat(path)
mtime = dt.datetime.fromtimestamp(st.st_mtime)
if mtime > ago:
print("True: ", fname, " at ", mtime.strftime("%H:%M %m/%d/%Y"))
shutil.move(path, dest)
def find_info(): #this first func. works fine.for root, dirs, files in os.walk(created):
for root, dirs, files in os,walk(origin_path):
for fname in files:
path = os.path.join(root, fname)
st = os.stat(path)
mtime = dt.datetime.fromtimestamp(st.st_mtime)
if mtime > ago:
print(True)
else:
print(False)
print (find_info())
print (move())
print (os.listdir(dest))
print (os.listdir(created))
The problem is that you are calling os.walk with a tkinter StringVar, but os.walk does not accept StringVars; it only accepts objects of type str, bytes, or os.PathLike (e.g. pathlib Path objects).
You can fix the error by using os.walk(origin_path.get()) instead of os.walk(origin_path). This gets the string from the StringVar and passes that to os.walk, instead of passing the StringVar to os.walk directly.

Expecting string, bytes, or os.PathLike or integer, not StringVar

I'm working on a project that monitors two selected folders and automatically moves files created or edited within the last twenty-four hours from Folder_A to Folder_B. It also will check the two folders manually when the user clicks the scan button. So far it will select the two folders, but when I click the scan button I get this error. How would I go about fixing the error?
My code is below the error. Please be understanding that I am still really new to python, so there might be quite a few really stupid mistakes in here.
import tkinter as tk
from tkinter import *
from tkinter import filedialog
import os,time
import datetime
import shutil
import datetime as dt
def browse_button():
# Allow user to select a directory and store it in global var
# called origin_path
global origin_path
filename = filedialog.askdirectory()
origin_path.set(filename)
print(filename)
def browse_button2():
# Allow user to select a directory and store it in global var
# called receiving_path
global receiving_path
filename = filedialog.askdirectory()
receiving_path.set(filename)
print(filename)
def submitFunction() :
for root, dirs,files in os.walk(origin_path.get()):
for fname in files:
path = os.path.join(fname, root)
st = os.stat(path)
mtime = dt.datetime.fromtimestamp(st.st_mtime)
shutil.move(path, receiving_path)
print('Submit button is clicked.')
root = Tk()
origin_path = StringVar()
receiving_path = StringVar()
#First Browse Button Label
lbl1 = Label(master=root,textvariable=origin_path)
lbl1.grid(row=0, column=1)
#Second Browse Button Label
lbl1_2 = Label(master=root,textvariable=receiving_path)
lbl1_2.grid(row=1, column=1)
lbl1_3 = Label(master=root)
lbl1_3.grid(row=2, column=1)
button = Button(text="Browse", command=browse_button)
button.grid(row=0, column=3)
button2 = Button(text="Browse", command=browse_button2)
button2.grid(row=1, column=3)
scan_btn=Button(text="Scan", command = lambda:submitFunction())
scan_btn.grid(row=2, column=7)
mainloop()
now = dt.datetime.now()
ago = now-dt.timedelta(hours=24)
strftime = "%H:%M %m/%d/%Y"
created = 'origin_path'
dest = 'receiving_path'
file_path = 'file:///'+os.getcwd()+'/' + ''
print("Last modified: %s" % time.ctime(os.path.getmtime(file_path)))
print("Created: %s" % time.ctime(os.path.getctime(file_path)))
for root, dirs,files in os.walk(origin_path.get()):
for fname in files:
path = os.path.join(root, fname)
st = os.stat(path)
mtime = dt.datetime.fromtimestamp(st.st_mtime)
if mtime > ago:
print("True: ", fname, " at ", mtime.strftime("%H:%M %m/%d/%Y"))
shutil.move(path, dest)
def find_info(): #this first func. works fine.for root, dirs, files in os.walk(created):
for root, dirs, files in os,walk(origin_path.get()):
for fname in files:
path = os.path.join(root, fname)
st = os.stat(path)
mtime = dt.datetime.fromtimestamp(st.st_mtime)
if mtime > ago:
print(True)
else:
print(False)
print (find_info())
print (move())
print (os.listdir(dest))
print (os.listdir(created))
Here's the error:
C:/Users/quirk/PycharmProjects/Trial_2
C:/Users/quirk/PycharmProjects/Trial_2/.idea
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\quirk\AppData\Local\Programs\Python\Python310\lib\tkinter\__init__.py", line 1921, in __call__
return self.func(*args)
File "C:\Users\quirk\AppData\Local\Programs\Python\Python310\Projects\File_transfer.py", line 63, in <lambda>
scan_btn=Button(text="Scan", command = lambda:submitFunction())
File "C:\Users\quirk\AppData\Local\Programs\Python\Python310\Projects\File_transfer.py", line 39, in submitFunction
shutil.move(path, receiving_path)
File "C:\Users\quirk\AppData\Local\Programs\Python\Python310\lib\shutil.py", line 791, in move
if os.path.isdir(dst):
File "C:\Users\quirk\AppData\Local\Programs\Python\Python310\lib\genericpath.py", line 42, in isdir
st = os.stat(s)
TypeError: stat: path should be string, bytes, os.PathLike or integer, not StringVar
As the message says, receiving_path is a StringVar object, not a string. To fetch the string value, you need to use .get():
shutil.move(path, receiving_path.get())

Get file details (complete file path) from the filename (only basename) existing as a text in tkinter Text widget

With the help of following code I am inserting the filename (file basename) in the tkinter Text widget and subsequently then trying to print the complete file path after the "Get Data" button is pressed.
import tkinter as tk
from tkinter.filedialog import askopenfilename
import os
root=tk.Tk()
ent=tk.Text(root)
ent.grid(row=1,column=0)
def addfile():
filename =askopenfilename(filetypes=(("Tiff files","*.tif"),("All files","*.*")))
ent.insert(tk.INSERT, '"' + os.path.basename(filename) + '"')
ent.insert(tk.INSERT, "\n")
def getfile():
print(ent.get("1.0", tk.END))
b=tk.Button(root,text="Select File",command=addfile)
b.grid(row=0,column=0)
b1 = tk.Button(root,text="Get Data",command=getfile)
b1.grid(row=2,column=0)
root.mainloop()
After running the above code only filenames are getting printed (without filepath).
Now basically what I want is that, after the "Get Data" button is pressed (where the contents of Text widget is read) then complete path of files should be printed.
Additional information:-
I know that if filenames would have been different then I could have used dictionary (key, value) pair to link basename of each file with its absolute path. But issue will come when different files present in different folder location but having same names are added to the Text widget.
As Cool Cloud has commented it is hard to give the exact answer you need, because you havent told us what is happening and what you expect/what to happen.
The way I read it is that you either want:
the whole filename, which you have recieved from the askopenfilename() to be inserted in the Text widget.
you want the whole filename to be printed when you click the Button b1, but the Text widget to be left as is.
1. I would change def addfile(): to
def addfile():
filename = askopenfilename()
ent.insert(tk.INSERT, '"' + filename + '"\n')
What this does is inserts the full file path rather than just the basename, i.e. it would insert "D:/example/help.tif" rather than just help.tif.
2. I would use the code below
root = tk.Tk()
def addfile():
filename = askopenfilename()
list_of_filenames.append(filename)
ent.insert(tk.INSERT, '"' + os.path.basename(filename) + '"\n')
def getfile():
for i in range(len(list_of_filenames)):
print(list_of_filesnames[i])
list_of_filenames = []
ent = tk.Text(root)
ent.grid(row=1, column=0)
b=tk.Button(root,text="Select File",command=addfile)
b.grid(row=0,column=0)
b1 = tk.Button(root,text="Get Data",command=getfile)
b1.grid(row=2,column=0)
root.mainloop()
What I have done is create a global list variable named list_of_filenames and in def addfile(): I added the line list_of_filenames.append(filename), this takes the file you selected, and the path, and add it to the list variable. Thus giving you a list with every file you select, and it can be accessed by any function you build because it is global.
The final change is to def getfile(): this can be done exactly how you would like to, I have written it to print each of the files individually on a seperate lines, without square brackets or quotation marks.
Using the same example as in part 1, if I selected a file with the path D:/example/help.tif the Text widget would read "help.tif" and when b1 is clicked D:/example/help.tif would be printed to the consol.
I will split my code up to try and explain what i've done.
The first 4 functions are to do the addfile(): plus the other thing you have asked for.
The first function split_filename(path): does what the fuction name says. It will take the path entered and create a list of the individual parts of the the path. (i.e. if you have D:/folder/example/help/test.tif it would return ['D:/', 'folder', 'example', 'help', 'test.tif'], you will see later that this is useful when you have 2 basenames that are the same.
def split_filename(path):
allParts = []
while 1:
parts = os.path.split(path)
if parts[0] == path:
allParts.insert(0, parts[0])
break
elif parts[1] == path:
allParts.insert(0, parts[1])
break
else:
path = parts[0]
allParts.insert(0, parts[1])
return allParts
check_if_fileBasename_in_current_content(current_content, selected_file_basename): again the function name tells you exactly what is does. This checks if the new selected file basename is already in the Text widget.
def check_if_fileBasename_in_current_content(current_content, selected_file_basename):
for line in current_content:
if line == '':
pass
elif line == selected_file_basename:
return True
The third if_true_split_path_for_basename(selected_file_path, selected_file_basename): is called if the new selected file basename already exists in the Text widget. The fuction takes the path for both the new selected file and the 1 already saved. If you have 2 files: D:/example1/help.tif(new selected) and D:/example2/help.tif(previously added) the new selected basename would become example2/help.tif instead of just help.tif. By doing this it makes it possible to distiquish the difference between the 2 files. At the end of the fuction the basename created thought the fuction is inserted into ent and added to the dictionary dict_of_filenames(this become useful when printing the paths when b1 is clicked.)
def if_true_split_path_for_baseline(selected_file_path, selected_file_basename):
basename_for_text_widget = []
if selected_file_path in dict_of_filenames:
pass
else:
for path, basename in dict_of_filenames.items():
if basename == selected_file_basename:
duplicate_path_split = split_filename(path)
selected_file_path_split = split_filename(selected_file_path)
for i in range(len(selected_file_path_split)):
duplicate_slice = duplicate_path_split[-(i + 1)]
selected_slice = selected_file_path_split[-(i + 1)]
if duplicate_slice == selected_slice:
basename_for_text_widget.insert(0, selected_slice)
else:
basename_for_text_widget.insert(0, selected_slice)
break
ent.insert(tk.INSERT, str('/'.join(basename_for_text_widget) + '\n'))
dict_of_filenames.update({selected_file_path: '/'.join(basename_for_text_widget)})
addFile() link all of the functions above, it: ask for a file; get the basename; get all of the current text is in the Text widget; checks if the basename already exists and if so call fuction 3 (above), and finally if it is a new basename it inserts the basename to ent and adds both path and basename to the dictionary.
def addFile():
selected_file_path = askopenfilename(filetypes=(("Tiff files", "*.tif"), ("All files", "*.*")))
selected_file_basename = os.path.basename(selected_file_path)
current_content = ent.get("1.0", tk.END).splitlines()
check1 = check_if_fileBasename_in_current_content(current_content, selected_file_basename)
basename_for_text_widget = []
if check1:
if_true_split_path_for_baseline(selected_file_path, selected_file_basename)
else:
basename_for_text_widget.append(selected_file_basename)
dict_of_filenames.update({selected_file_path: ''.join(basename_for_text_widget)})
ent.insert(tk.INSERT, str(' '.join(basename_for_text_widget) + '\n'))
Next is the getFile(): takes the the content of ent and then takes the basename and prints the corresponding path.
def getFile():
current_content = ent.get(1.0, tk.END).splitlines()
for path, basename in dict_of_filenames.items():
if basename in current_content:
print(path)
The final change you need to do is to create the global dictionary
by adding dict_of_filename = {} Insert below the def getFile(): fuction, with no indentation like the Text and Button variables
Everything else stays as is.

Multiple Paths Traversed and Displayed Filed type in Maya Menu with Python

I'm new here so bare in mind that and I hope my questions are clearly asked for you lot to help me out. I am trying to alter Brent Tylers Dropbox script so that I will be able to list Python under Python, Mel under Mel and so on(eventually plugins and other files too but not for now)
Ok so my directory is like so:
1.
sf=C:/users/scripts/ a.py + b.mel
pf=C:/users/scripts/Python/c.py
mf=C:/users/scripts/Mel/d.mel
(These are the folders my scripts will be placed in)
Code :
absoluteFiles = []
relativeFiles = []
folders = []
allFiles = []
currentFile = ''
for root, dirs, files in os.walk(sf):
for x in files:
correct = root.replace('\\', '/')
currentFile = (correct + '/' + x)
allFiles.append(currentFile)
if currentFile.endswith('.mel'):
relativeFiles.append(currentFile.replace((mf + '/'), ""))
if currentFile.endswith('.py'):
relativeFiles.append(currentFile.replace((pf + '/'), ""))
relativeFiles.sort()
for relativeFile in relativeFiles:
split = relativeFile.split('/')
fileName = split[-1].split('.')
i=0
while i<(len(split)):
### Create Folders ###
if i==0 and len(split) != 1:
if cmds.menu(split[i] ,ex=1) == 0:
cmds.menuItem(split[i], p=PadraigsTools, bld=1, sm=1, to=1, l=split[i])
if i > 0 and i < (len(split)-1):
if cmds.menu(split[i] ,ex=1) == 0:
cmds.menuItem(split[i], p=split[i-1], bld=1, sm=1, to=1, l=split[i])
### Create .mel Files ###
if fileName[-1] == 'mel':
if i==len(split)-1 and len(split) > 1:
scriptName = split[-1].split('.')
temp1 = 'source ' + '"' + sf + '/' + relativeFile + '"; ' + scriptName[0]
command = '''mel.eval(''' + "'" + temp1 + '''')'''
cmds.menuItem(split[i], p=split[i-1], c=command, l=split[i])
if i==len(split)-1 and len(split) == 1:
scriptName = split[-1].split('.')
temp1 = 'source ' + '"' + sf + '/' + relativeFile + '"; ' + scriptName[0]
command = '''mel.eval(''' + "'" + temp1 + '''')'''
cmds.menuItem(split[i], p=Mel, c=command, l=split[i])
### Create .py Files ###
if fileName[-1] == 'py':
if i==len(split)-1 and len(split) > 1:
command = 'import ' + fileName[0] + '\n' + fileName[0] + '.' + fileName[0]+ '()'
cmds.menuItem(split[i], p=split[i-1], c=command, l=split[i])
if i==len(split)-1 and len(split) == 1:
command = 'import ' + fileName[0] + '\n' + fileName[0] + '.' + fileName[0]+ '()'
cmds.menuItem(split[i], p=Python, c=command, l=split[i])
i+=1
So far I can print out individually (sf, pf, mf) to the corresponding Directory but I cant list out everything at once and the files under sf will not show at all. regarding the folders created it ends up very odd. sometimes i would get a duplicate folder as a submenu and if i use sf it give me C:/.
After days and hours of research trying to mend this script I have found no answer including
from itertools import chain
paths = (mf, sf, pf)
for path, dirs, files in chain.from_iterable(os.walk(path) for path in paths):
::QUESTION::
Is there a way i can put this together sanely so that new folders will show up with their contents on refresh as a submenu and the files will show up and allow me to execute them from their corresponding submenu.
I would appreciate any help possible including down votes haha. And bare in mind I don't want you to hand me the answer on a golden spoon because I wont know what is corrected or needs to be :)
Thanks Greatly
-- Padraig
There's a couple of things you can do to simplify things a bit.
First, it's a good idea to make this as data-driven as possible so you don't have to re-write it if your needs change. This does more or less what you do, but collects the results into a dictionary where the key are the root paths you supplied and the values are lists of relative paths:
def find_files(root, extensions = ('mel', 'py')):
def clean_path(*p):
return "/".join(p).replace('\\', '/')
for root, _, files in os.walk(root):
used = [f for f in files if f.split(".")[-1] in extensions]
for u in used:
yield clean_path(root, u)
def relativize(abs, roots):
low_roots = map (str.lower, roots) # all lower for comparison
for root, low_root in zip(roots,low_roots):
if abs.lower().startswith(low_root):
return root, abs[len(root):]
return ("", abs)
relative_paths = find_files('c:/users/scripts')
root_dict = {}
for item in relative_paths :
folder, file = relativize(item, ('C:/users/scripts/Python/', 'C:/users/scripts/Mel/', 'C:/users/scripts/'))
if not folder in root_dict:
root_dict[folder] = []
root_dict[folder].append(file)
So now you have a dictionary with a bunch of root folders and lists of relative paths (files that were not in any relative path you supplied are keyed to empty string and show up as absolute paths). You can make the menus in a very generic way because they are all in the same format. If you need the entire list, you can get it like this:
results = []
for each_root in root_dict:
for relpath in root_dict[each_root]:
results.append(each_root + relpath)
For creating the actual menus, you want to use a single function and bind it to the filename for each menu item as you make it. This is a slightly tricky topic (more detail here). The easy way to do this is to use a functools.partial object, which bundles a command and a bunch of arguments into an object which looks like a function: you can create a partial and attach it to the command of your menu items so they all call the same function with their individual arguments. Here's a simple example using the variables from above and a menubar; you can see how to adapt it to other kinds of menus pretty easily:
from functools import partial
# call this on every button selection
def test(filepath, ignore):
# maya will send "test(name, False)"; we just ignore the 'False'
print "Here's where I would reload", filepath
example = cmds.window(title = 'example')
menubar = cmds.menuBarLayout()
for name in folder_names:
menuname = name
if menuname:
menuname = menuname.split("/")[-2] # we used trailing slashes
else:
menuname = "root"
cmds.menu(label = menuname)
file_names = root_dict[name]
file_names.sort()
for fn in file_names:
mi = cmds.menuItem(label = fn, command = partial(test, fn))
cmds.setParent(menubar)

Categories

Resources