Background
This is a feature that I have wanted to see in Jupyter notebook for quite some time. I'm sure that others have built similar things but I haven't been able to find them on SO, Github, CodeReview or the rest of the searchable internet.
Approach
I used ipywidgets.Button
as a base class and added a traitlet called files. This traitlet receives a list of files as strings from tkinter.filedialog.askopenfilename
. When the button is clicked the file dialog pops up the user selects files and then can access that list of strings as an attribute/traitlet on the button instance.
import traitlets
from ipywidgets import widgets
from IPython.display import display
from tkinter import Tk, filedialog
class SelectFilesButton(widgets.Button):
"""A file widget that leverages tkinter.filedialog."""
def __init__(self):
super(SelectFilesButton, self).__init__()
# Add the selected_files trait
self.add_traits(files=traitlets.traitlets.List())
# Create the button.
self.description = "Select Files"
self.icon = "square-o"
self.style.button_color = "orange"
# Set on click behavior.
self.on_click(self.select_files)
@staticmethod
def select_files(b):
"""Generate instance of tkinter.filedialog.
Parameters
----------
b : obj:
An instance of ipywidgets.widgets.Button
"""
# Create Tk root
root = Tk()
# Hide the main window
root.withdraw()
# Raise the root to the top of all windows.
root.call('wm', 'attributes', '.', '-topmost', True)
# List of selected fileswill be set to b.value
b.files = filedialog.askopenfilename(multiple=True)
b.description = "Files Selected"
b.icon = "check-square-o"
b.style.button_color = "lightgreen"
Example Usage
Displaying the button
my_button = SelectFilesButton()
my_button # This will display the button in the context of Jupyter Notebook
Retrieving the file list from the button.
# In a different cell of the same Jupyter Notebook You can access the file list by using the following:
my_button.files
Questions
These are just some suggestions.
1) Does this work on your machine? If so throw me an upvote! If not please specify what versions you are working with so I can extend.
2) Are there any general overall improvements that can be made?
3) Is there any redundancy that I missed?
4) Does this code follow best practices?