I recently made some tools implemented in python. Since it is now possible to start from the console or double-click, I wanted to set it as a windows shortcut (described later) so that it could be started conveniently (I plan to create a scraping tool soon, so to prepare for it).
However, if you set a shortcut for each file with the extension py, it may cause batting and inadvertent startup. I decided to create a GUI tool that can be executed by listing the python files under the set folder and selecting from them.
I heard that there is a convenient library called tkinter for GUI creation of python, so I will use it.
A file with the extension py or pyw is associated with python.exe (or pythonw.exe). What is an association? → http://www.first-pclife.com/pckiso/kanrenduketoha.html
-Recursively searches python files under the specified folder and stores them in a data type such as a list. -Create a GUI that lists and displays data in a table -Implement a function that executes the file selected from the table -Set the tool with the above conditions as a windows shortcut so that it can be started.
・ Windows 10 -Python 3.7.0
It looks like this when started.
Execute the specified python file by pressing the execute button (same behavior as double-click startup).
CallPythonFile.py
import glob
import os
import subprocess
import tkinter as tk
import tkinter.ttk as ttk
def main():
#Creating a root frame
root = tk.Tk()
root.title(u"Python program execution assist")
#Root window size setting
root.geometry("1200x500")
#Set selectable python file as dictionary value
#All python files directly under the specified folder (search recursively)
myPath = r'C:\Users\UserName\Test\ToolBox'
myDic = {}
if os.path.isdir(myPath):
for file in glob.glob(myPath + '\\**', recursive=True):
nameRoot, ext = os.path.splitext(os.path.basename(file))
if os.path.isfile(file) and ext in ('.py', '.pyw') and nameRoot != '__init__':
myDic[os.path.abspath(file)] = os.path.basename(file)
#Frame setting
frame1 = ttk.Frame(root, width=1200, height=300, padding=10)
frame1.grid()
frame1.columnconfigure(0, weight=1)
frame1.grid_propagate(False)
# //////Tree view settings
tree = ttk.Treeview(frame1, height=8, selectmode="browse")
#Create column index
tree["columns"] = (1, 2)
#Table style settings
tree["show"] = "headings"
#Settings for each column
tree.column(1, width=250)
tree.column(2, width=1000)
#Header settings for each column
tree.heading(1, text="file name")
tree.heading(2, text="path")
#Create record
for k, v in sorted(myDic.items(), key=lambda x: x[1]):
tree.insert("", "end", values=(str(v), str(k)))
#Arrangement of tree view
tree.grid(row=0, column=0, columnspan=2, padx=5, pady=5, sticky=tk.N + tk.S + tk.E + tk.W)
# //////////////////////
#Scrollbar settings
hscrollbar = ttk.Scrollbar(frame1, orient=tk.HORIZONTAL, command=tree.xview)
vscrollbar = ttk.Scrollbar(frame1, orient=tk.VERTICAL, command=tree.yview)
tree.configure(xscrollcommand=hscrollbar.set)
tree.configure(yscrollcommand=vscrollbar.set)
vscrollbar.grid(row=0, column=1, columnspan=1, padx=5, pady=5, sticky=tk.NS)
hscrollbar.grid(row=1, column=0, columnspan=1, padx=5, pady=5, sticky=tk.EW)
#Creating a button
button = tk.Button(text="Run", command=lambda: RunPythonFile(root, tree))
#Button placement
button.grid(padx=5, pady=5, )
root.mainloop()
def RunPythonFile(root, tree):
#Get the file path selected from the table
selectedItems = tree.selection()
filePath = tree.item(selectedItems[0])['values'][1]
#Frame close
root.destroy()
#py file call execution
subprocess.check_call(['python', filePath])
if __name__ == '__main__':
main()
for file in glob.glob(myPath + '\\**', recursive=True):
Recursive search can be implemented quite easily by using the glob method.
When using, add ** to the path of the parent folder and set recursive to true.
if os.path.isfile(file) and ext in ('.py', '.pyw') and nameRoot != '__init__':
Exclude folders and extract only those with the extension py or pyw.
I don't need init.py, so I'll remove it.
tree = ttk.Treeview(frame1, height=8, selectmode="browse")
Since it works with the scroll bar, it is a child object of the frame object. Setting selectmode = "browse" is convenient because you can select only one item from the created table.
for k, v in sorted(myDic.items(), key=lambda x: x[1]):
tree.insert("", "end", values=(str(v), str(k)))
Loop to the ascending sort of value (return value is list) The item is being taken out. I used this as a reference. https://qiita.com/shizuma/items/40f1fe4702608db40ac3
button = tk.Button(text="Run", command=lambda: RunPythonFile(root, tree))
If you do not bite the anonymous function lambda (when you specify the function directly in command), the function will be executed when the GUI is displayed, so it is NG.
filePath = tree.item(selectedItems[0])['values'][1]
All selected items The first item in selectedItems is the item actually selected. If there are multiple selections, there are also after [1], but since select mode = "browse" is set, only one. ['values'] [1] extracts the file path from the list of values (file name and file path).
#Scrollbar settings
hscrollbar = ttk.Scrollbar(frame1, orient=tk.HORIZONTAL, command=tree.xview)
vscrollbar = ttk.Scrollbar(frame1, orient=tk.VERTICAL, command=tree.yview)
tree.configure(xscrollcommand=hscrollbar.set)
tree.configure(yscrollcommand=vscrollbar.set)
vscrollbar.grid(row=0, column=1, columnspan=1, padx=5, pady=5, sticky=tk.NS)
hscrollbar.grid(row=1, column=0, columnspan=1, padx=5, pady=5, sticky=tk.EW)
Setting up the scrollbar was pretty hard. At first I used the pack () method to place each component, That just doesn't work.
Then I tried the gird () method. However, after all it shifts (x-axis scrolling works but y-axis does not work. → y-axis works but x-axis works ...)
Finally, I found the following article. [Python 3.x --python ttk treeview does not change background color | teratail](https://ja.stackoverflow.com/questions/56104/treeview%E5%86%85%E3%83%AA%E3% 82% B9% E3% 83% 88% E3% 82% 92% E5% 9B% BA% E5% AE% 9A% E5% B9% 85% E3% 81% AB% E3% 81% 97-% E6% A8 % AA% E3% 82% B9% E3% 82% AF% E3% 83% AD% E3% 83% BC% E3% 83% AB% E3% 83% 90% E3% 83% BC% E3% 82% 92 % E6% 9C% 89% E5% 8A% B9% E3% 81% AB% E3% 81% 97% E3% 81% 9F% E3% 81% 84)
I referred to this and managed to implement it as follows and it worked.
#Frame setting
frame1 = ttk.Frame(root, width=1200, height=300, padding=10)
frame1.grid()
frame1.columnconfigure(0, weight=1)
frame1.grid_propagate(False)
If anyone knows how to implement it well with the pack method, please let me know.
① Store the shortcut of CallPythonFile.py in the following folder
C:\ProgramData\Microsoft\Windows\Start Menu\Programs
② Right-click on the shortcut to Specify your favorite key in the "Shortcut key" item.
③ Press the key and check that the GUI is displayed.
Click here for the latest tools and source code ↓ https://github.com/dede-20191130/CreateToolAndTest/tree/master/Tool_Python/CallPythonFile
Please comment if you have any supplements.
Recommended Posts