How to do it...

Add the following code to our GUI in the create_widgets() method towards the bottom where we created Tab Control 2. The parent of the new widget frame is tab2, which we created at the very beginning of the create_widgets() method. As long as you place the following code physically below the creation of tab2, it will work:

    ########################################################### 
def create_widgets(self):
# Create Tab Control
tabControl = ttk.Notebook(self.win)
# Add a second tab
tab2 = ttk.Frame(tabControl)
# Make second tab visible
tabControl.add(tab2, text='Tab 2')

# Create Manage Files Frame
mngFilesFrame = ttk.LabelFrame(tab2, text=' Manage Files: ')
mngFilesFrame.grid(column=0, row=1, sticky='WE', padx=10, pady=5)

# Button Callback
def getFileName():
print('hello from getFileName')

# Add Widgets to Manage Files Frame
lb = ttk.Button(mngFilesFrame, text="Browse to File...",
command=getFileName)
lb.grid(column=0, row=0, sticky=tk.W)

file = tk.StringVar()
self.entryLen = scrol_w
self.fileEntry = ttk.Entry(mngFilesFrame, width=self.entryLen,
textvariable=file)
self.fileEntry.grid(column=1, row=0, sticky=tk.W)

logDir = tk.StringVar()
self.netwEntry = ttk.Entry(mngFilesFrame,
width=self.entryLen,
textvariable=logDir)
self.netwEntry.grid(column=1, row=1, sticky=tk.W)

def copyFile():
import shutil
src = self.fileEntry.get()
file = src.split('/')[-1]
dst = self.netwEntry.get() + ''+ file
try:
shutil.copy(src, dst)
msg.showinfo('Copy File to Network', 'Succes:
File copied.')
except FileNotFoundError as err:
msg.showerror('Copy File to Network',
'*** Failed to copy file! *** ' +
str(err))
except Exception as ex:
msg.showerror('Copy File to Network',
'*** Failed to copy file! *** ' + str(ex))

cb = ttk.Button(mngFilesFrame, text="Copy File To : ",
command=copyFile)
cb.grid(column=0, row=1, sticky=tk.E)

# Add some space around each label
for child in mngFilesFrame.winfo_children():
child.grid_configure(padx=6, pady=6)

This will add two buttons and two entries to Tab 2 of our GUI.

We are not yet implementing the functionality of our button callback function.

Running the code creates the following GUI:

Clicking the Browse to File... button currently prints to the console:

We can use tkinter's built-in file dialogs, so let's add the following import statements to the top of our Python GUI module:

from tkinter import filedialog as fd 
from os import path

We can now use the dialogs in our code. Instead of hardcoding a path, we can use Python's os module to find the full path to where our GUI module resides:

def getFileName(): 
print('hello from getFileName')
fDir = path.dirname(__file__)
fName = fd.askopenfilename(parent=self.win, initialdir=fDir)

Clicking the browse button now opens up the askopenfilename dialog:

We can now open a file in this directory or browse to a different directory. After selecting a file and clicking the Open button in the dialog, we will save the full path to the file in the fName local variable.

It would be nice if, when we opened our Python askopenfilename dialog widget, we would automatically default to a directory so that we would not have to browse all the way to where we were looking for a particular file to be opened.

It is best to demonstrate how to do this by going back to our GUI Tab 1, which is what we will do next.

We can default the values into Entry widgets. Back on our Tab 1, this is very easy. All we have to do is add the following two lines of code to the creation of the Entry widget:

    # Adding a Textbox Entry widget 
self.name = tk.StringVar()
self.name_entered = ttk.Entry(mighty, width=24, textvariable=self.name)
self.name_entered.grid(column=0, row=1, sticky='W')
self.name_entered.delete(0, tk.END)
self.name_entered.insert(0, '< default name >')

When we now run the GUI, the name_entered entry has a default value:

We can get the full path to the module we are using with the following Python syntax, and then we can create a new subfolder just below it. We can do this as a module-level global, or we can create the subfolder within a method:

    # Module level GLOBALS 
GLOBAL_CONST = 42
fDir = path.dirname(__file__)
netDir = fDir + 'Backup'

def __init__(self):
self.createWidgets()
self.defaultFileEntries()

def defaultFileEntries(self):
self.fileEntry.delete(0, tk.END)
self.fileEntry.insert(0, fDir)
if len(fDir) > self.entryLen:
self.fileEntry.config(width=len(fDir) + 3)
self.fileEntry.config(state='readonly')

self.netwEntry.delete(0, tk.END)
self.netwEntry.insert(0, netDir)
if len(netDir) > self.entryLen:
self.netwEntry.config(width=len(netDir) + 3)

We set the defaults for both the Entry widgets, and after setting them, we make the local file Entry widget read-only.

This order is important. We have to first populate the entry before we make it read-only.

We are also selecting Tab 2 before calling the main event loop and no longer set the focus into the Entry of Tab 1. Calling select on our tkinter notebook is zero-based, so by passing in the value of 1, we select Tab 2:

    # Place cursor into name Entry 
# name_entered.focus()
tabControl.select(1)

Running GUI_copy_files.py results in the following screenshot:

As we are not all on the same network, this recipe will use the local hard drive as an example for a network.

A UNC path is a Universal Naming Convention (UNC) and what this means is that by using double backslashes instead of the typical C:, we can access a server on a network.

You just have to use the UNC and replace C: with \<servername><folder>.

This example can be used to back up our code to a backup directory, which we can create if it does not exist by using os.makedirs:

    # Module level GLOBALS 
GLOBAL_CONST = 42

from os import makedirs
fDir = path.dirname(__file__)
netDir = fDir + 'Backup'
if not path.exists(netDir):
makedirs(netDir, exist_ok = True)

After selecting a file to copy to somewhere else, we import the Python shutil module. We need the full path to the source of the file to be copied and a network or local directory path, and then we append the file name to the path where we will copy it, using shutil.copy.

Shutil is short-hand notation for shell utility.

We also give feedback to the user via a message box to indicate whether the copying succeeded or failed. In order to do this, import messagebox and alias it msg.

In the next code, we will mix two different approaches of where to place our import statements. In Python, we have some flexibility that other languages do not provide. We typically place all of the import statements towards the very top of each of our Python modules so that it is clear which modules we are importing. At the same time, a modern coding approach is to place the creation of variables close to the function or method where they are first being used.

In the next code, we import the message box at the top of our Python module, but then we also import the shutil Python module in a function. Why would we wish to do this? Does this even work? The answer is yes, it does work, and we are placing this import statement into a function because this is the only place in our code where we actually do need this module.

If we never call this method then we will never import the module this method requires. In a sense, you can view this technique as the lazy initialization design pattern. If we don't need it, we don't import it until we really do require it in our Python code. The idea here is that our entire code might require, let's say, 20 different modules. At runtime, which modules are really needed depends upon the user interaction. If we never call the copyFile() function, then there is no need to import shutil.

Once we click the button that invokes the copyFile() function in this function, we import the required module:

    from tkinter import messagebox as msg
def copyFile():
import shutil #import module within function
src = self.fileEntry.get()
file = src.split('/')[-1]
dst = self.netwEntry.get() + ''+ file
try:
shutil.copy(src, dst)
msg.showinfo('Copy File to Network', 'Succes: File
copied.')
except FileNotFoundError as err:
msg.showerror('Copy File to Network',
'*** Failed to copy file! *** ' +
str(err))
except Exception as ex:
msg.showerror('Copy File to Network',
'*** Failed to copy file! *** ' + str(ex))

When we now run our GUI, browse to a file, and click Copy, the file is copied to the location we specified in our Entry widget:

If the file does not exist or we forgot to browse to a file and are trying to copy the entire parent folder, the code will let us know this as well because we are using Python's built-in exception handling capabilities:

Our new Entry widgets did expand the width of the GUI. While it is sometimes nice to be able to see the entire path, at the same time, it pushes other widgets, making our GUI look not so good. We can solve this by restricting the width parameter of our Entry widgets:

This results in the following GUI size. We can right-arrow in the enabled Entry widget to get to the end of this widget:

GUI_copy_files_limit.py

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.143.239.44