Problems while Handling Button Event in Python - python

How to Handle a Button Click Event in Python? I am New to python and trying to develop Zip Extractor tool.i've handled the Btn1 and Btn2 Properly but the 3'rd one is giving me errors.("name res1 is not defined") Here is the code
i've Wrote as follows: Plz Help Me as i am a noobie :| Thanks In Adv :)
from tkinter import *
from tkinter.filedialog import askdirectory
import os, zipfile
extension = ".zip"
PASSWORD = "virus007"
global res1
global res2
window = Tk()
window.title("Welcome Zip_Extractor_Utility")
window.geometry('640x260')
lbl1 = Label(window, text="Select Source Location:" ,font=("Arial Bold", 12))
lbl2 = Label(window, text="Select Destination Location:" ,font=("Arial Bold", 12))
lbl1.grid(column=0, row=7)
lbl2.grid(column=50, row=7)
def clicked1():
res1 = askdirectory()
print(res1)
return res1
btn1 = Button(window, text="Browse" , command=clicked1)
btn1.grid(column=1, row=7)
def clicked2():
res2 = askdirectory()
print(res2)
return res2
btn2 = Button(window, text="Browse" , command=clicked2)
btn2.grid(column=51, row=7)
##lbl3 = Label(window, text="Extract:" ,font=("Arial ", 12))
##lbl3.grid(column=70, row=7)
def clicked3():
os.chdir(res1) # change directory from working dir to dir with files
for item in os.listdir(res1): # loop through items in dir
if item.endswith(extension): # check for ".zip" extension
file_name = os.path.abspath(item) # get full path of files
zip_ref = zipfile.ZipFile(file_name) # create zipfile object
zip_ref.setpassword(PASSWORD)
zip_ref.extractall(res2) # extract file to dir
zip_ref.close() # close file
#os.remove(file_name) # delete zipped file
print('done')
btn3 = Button(window, text="Extract" , command=clicked3)
btn3.grid(column=71, row=7)
window.mainloop()

In your case, just check if res1 and res2 is defined in clicked3 function. Maybe with 'res1' in vars() and 'res2' in vars(). If it's not defined, warn users that they need to specify source and destination folder first.

Related

Tkinter theme is not working, just displays as regular

I'm trying to use the theme "sun valley" for a python-based installer that i'm working on. I have all the .tcl files installed and everything should be working, but its not. I even tried to use the built in styles
here's my code:
from tkinter import *
from tkinter import ttk
from tkinter.ttk import *
import os
director = os.path.dirname(__file__)
friendlyName = "python"
file = ""
import shutil
global User
try:
User = os.getlogin()
except:
User="home"
from tkinter import *
from tkinter import filedialog
from os import path
path = fr"C:\{User}\AppData\Local\{friendlyName}"
def install():
try:
os.mkdir(path)
except:
pass
shutil.copy(file, path)
#E1 = Entry(top, bd =5)
window = Tk()
# Just simply import the azure.tcl file
style = ttk.Style(window)
dir_path = os.path.dirname(os.path.realpath(__file__))
window.tk.call('source', os.path.join(dir_path, 'theme\dark.tcl'))
print(os.path.join(dir_path, 'theme\dark.tcl'))
#window.tk.call("set_theme", "dark")
style.theme_use('sun-valley-dark')
window.geometry("600x400")
window.rowconfigure(20)
window.columnconfigure(20)
def askdir():
direct = filedialog.askdirectory()
path = direct
textBox.delete(0, END)
textBox.insert(0, path)
#textBox.set(path)
window.update_idletasks()
window.title(f"{friendlyName} install")
chooseText = Label(window, text=f"choose a place for {friendlyName} to be installed")
chooseText.grid(column=2, row=0)
chooseButton = Button(window, text="choose path", command=askdir)
chooseButton.grid(column=1, row=3)
textBox = Entry(window, text=f"{path}")
textBox.insert(0, path)
textBox.grid(column=2, row=3)
chooseButton = Button(window, text="install", command=install)
chooseButton.grid(column=3, row=4)
chooseButton = Button(window, text="quit", command=window.destroy)
chooseButton.grid(column=1, row=4)
window.mainloop()
heres what outputs:
Need to use ttk widgets
instead of chooseText = Label(window, text=f"choose a place for {friendlyName} to be installed")
it would be chooseText = ttk.Label(window, text=f"choose a place for {friendlyName} to be installed")
then the style will show up!

python tkinter infinite loop freezes

im currently making a tkinter app that auto backup files by watching the last mod
time of the file. code is as below.
from tkinter import *
from tkinter import filedialog
import shutil
import os
from datetime import datetime
app = Tk()
app.title("7dtd auto backup")
app.geometry("800x500")
stopsign = False
def stop():
global stopsign
stopsign = True
def getSrcFolderPath():
folder_selected = filedialog.askopenfilename()
src_text.set(folder_selected)
def getDstFolderPath():
folder_selected = filedialog.askdirectory()
dst_text.set(folder_selected)
def watchpath(file, folder):
global stopsign
file = file.get()
folder = folder.get()
backupnum = 1
if file != "":
lastmtime = os.path.getmtime(file)
while stopsign == False:
if os.path.getmtime(file) != lastmtime:
lastmtime = os.path.getmtime(file)
shutil.copytree(os.path.dirname(file), folder+"/backup"+str(backupnum))
backupnum += 1
src_text = StringVar() #source file selector
src_label = Label(app, text="save file")
src_label.grid(row=0, column=0)
src_entry = Entry(app, textvariable=src_text)
src_entry.grid(row=0, column=1)
src_btn = Button(app, text="browse", width=12, command=lambda: getSrcFolderPath())
src_btn.grid(row=0, column=2)
dst_text = StringVar()
dst_label = Label(app, text="destination folder")
dst_label.grid(row=0, column=3)
dst_entry = Entry(app, textvariable=dst_text)
dst_entry.grid(row=0, column=4)
dst_btn = Button(app, text="browse", width=12, command=lambda: getDstFolderPath())
dst_btn.grid(row=0, column=5)
start_btn = Button(app, text="start", width=12, command=lambda: watchpath(src_text, dst_text))
start_btn.grid(row=2, column=0)
end_btn = Button(app, text="end", width=12, command=lambda: stop())
end_btn.grid(row=2, column=1)
app.mainloop()
the idea is that im setting an infinite loop for the function to keep fetching the last mod time of the file until it has changed, but doing so will make my app freeze during the loop, which means that the app can only be stopped by closing. Is there a way to make it not freeze while still maintaining the function of detecting the change in last mod time?
Much appreciated!
The tkinter package offers a widget.after() function that allows you to call a function of your choice after a delay of X milliseconds. It's signature is as follows: w.after(delay_ms, callback=None, *args_for_your_function)
To make your code work, you can declare lastmtime as a global variable at the start of your code and then change your watchpatch function to the following:
def watchpath(fileVar, folderVar):
print("watchpatch firing...")
global stopsign
global lastmtime
if stopsign:
stopsign = False
print("Stopping watchpath!")
return
file = fileVar.get()
folder = folderVar.get()
backupnum = 1
if file != "" and os.path.getmtime(file) != lastmtime:
lastmtime = os.path.getmtime(file)
while os.path.exists(folder+"/backup"+str(backupnum)):
backupnum += 1
print("Copying folder contents to backup folder...")
shutil.copytree(os.path.dirname(file), folder+"/backup"+str(backupnum))
backupnum += 1
app.after(1000, watchpath, fileVar, folderVar)
Points to note:
Your program actually seems to copy the entire contents of the srcfile directory to the specified backup directory, not just the individual file. I've left this logic as-is, but you might want to change it if your goal is to backup just the one file.
I added in some basic print statements to help you understand what's happening. Remove these once you're good to go.

Get the entry directory as a string in Tkinter Python

I am trying to make a Windows software using Tkinter from Python, the purpose of this app is to move specific types of files to a specified directory.
But the error comes here, it looks like that my move function ins't getting my entry text and also the extension text, so thats why I think there is the error, the code is here....
import tkinter.filedialog as filedialog
import tkinter as tk
import os
import shutil
def input_source():
input_path = tk.filedialog.askdirectory()
input_entry.delete(1, tk.END) # Remove current text in entry
input_entry.insert(0, input_path) # Insert the 'path'
def output():
output_path = tk.filedialog.askdirectory()
output_entry.delete(1, tk.END) # Remove current text in entry
output_entry.insert(0, output_path) # Insert the 'path'
def move():
files = os.listdir(input_entry.get())
for file in files: # for every file in the source directory
file_name, extension = os.path.splitext(file) # lets split the name of the file and its extension
if extension == f".{file_extension.get()}": # knowing what type of extension or type of file, lets just move
# those
# files to the new directory
shutil.move(f"{input_entry.get()}/{file}", output_entry.get())
else: # if there are any files with that extension, lets just pass\skip\terminate the process
pass
master = tk.Tk()
top_frame = tk.Frame(master)
bottom_frame = tk.Frame(master)
line = tk.Frame(master, height=1, width=400, bg="grey80", relief='groove')
# input path
input_path = tk.Label(top_frame, text="Input File Path:")
input_entry = tk.Entry(top_frame, text="", width=40)
browse1 = tk.Button(top_frame, text="Browse", command=input_source)
# output path
output_path = tk.Label(bottom_frame, text="Output File Path:")
output_entry = tk.Entry(bottom_frame, text="", width=40)
browse2 = tk.Button(bottom_frame, text="Browse", command=output)
# File extension
file_extension_ = tk.Label(bottom_frame, text="File type:")
file_extension = tk.Entry(bottom_frame, text="", width=40)
file_extension.insert(0, 'Type file extension: .')
move = tk.Button(bottom_frame, text='Move!', command=move)
top_frame.pack(side=tk.TOP)
line.pack(pady=10)
bottom_frame.pack(side=tk.BOTTOM)
input_path.pack(pady=5)
input_entry.pack(pady=5)
browse1.pack(pady=5)
output_path.pack(pady=5)
output_entry.pack(pady=5)
browse2.pack(pady=5)
file_extension.pack(pady=5)
file_extension.pack(pady=5)
move.pack(pady=20, fill=tk.X)
master.mainloop()
Simplify this and it should work. If you're just trying to move files to the typed path, why not do it this way?
from tkinter import *
import os
root = Tk()
root.title("File Mover")
def move_file():
firstpath = entry1.get()
secondpath = entry2.get()
os.replace(firstpath, secondpath)
label1 = Label(text="Enter File Directory to Move")
label2 = Label(text="Enter New File Directory")
entry1 = Entry(width=20, justify="center")
entry2 = Entry(width=20, justify="center")
button = Button(text="Move File", command=move_file)
label1.grid(row=0, column=0)
label2.grid(row=1,column=0)
entry1.grid(row=0,column=1)
entry2.grid(row=1, column=1)
button.grid(row=2,column=0)
root.mainloop()
this requires they include the name of the file in the path, but I guarantee that it will get the text, and that it works moving the files on my machine.

How to use class and self here to get two different entries?

With my current code, it does not matter whether I click on "Input Folder" - Change or "JukeBox" change the result always gets displayed in "JukeBox" entry. This is incorrect, using class and self how can I change the code to display result from "Input Folder" - Change in "Input Folder" entry and the result from "Jukbox" - Change in "Jukebox" entry?
Also, how can I save the selected folders to a file so that it is there on app exit and re open?
My code:
import os
from tkinter import *
from tkinter import filedialog
inPut_dir = ''
jukeBox_dir = ''
def inPut():
opendir = filedialog.askdirectory(parent=root,initialdir="/",title='Input Folder')
inPut_dir = StringVar()
inPut_dir = os.path.abspath(opendir)
entry.delete(0, END)
entry.insert(0, inPut_dir)
def jukeBox():
opendir = filedialog.askdirectory(parent=root,initialdir="/",title='JukeBox')
jukeBox_dir = StringVar()
jukeBox_dir = os.path.abspath(opendir)
entry.delete(0, END)
entry.insert(0, jukeBox_dir)
root = Tk()
root.geometry("640x240")
root.title("Settings")
frametop = Frame(root)
framebottom = Frame(root)
frameright = Frame(framebottom)
text = Label(frametop, text="Input Folder").grid(row=5, column=2)
entry = Entry(frametop, width=50, textvariable=inPut_dir)
entry.grid(row=5,column=4,padx=2,pady=2,sticky='we',columnspan=20)
text = Label(frametop, text="JukeBox").grid(row=6, column=2)
entry = Entry(frametop, width=50, textvariable=jukeBox_dir)
entry.grid(row=6,column=4,padx=2,pady=2,sticky='we',columnspan=20)
ButtonA = Button(frametop, text="Change", command=inPut).grid(row=5, column=28)
ButtonB = Button(frametop, text="Change", command=jukeBox).grid(row=6, column=28)
ButtonC = Button(frameright, text="OK").grid(row=5, column=20, padx=10)
ButtonD = Button(frameright, text="Cancel").grid(row=5, column=15)
frametop.pack(side=TOP, fill=BOTH, expand=1)
framebottom.pack(side=BOTTOM, fill=BOTH, expand=1)
frameright.pack(side=RIGHT)
root.mainloop()
See attached image:enter image description here
Your code has both:
entry = Entry(frametop, width=50, textvariable=inPut_dir)
entry.grid(row=5,column=4,padx=2,pady=2,sticky='we',columnspan=20)
and
entry = Entry(frametop, width=50, textvariable=jukeBox_dir)
entry.grid(row=6,column=4,padx=2,pady=2,sticky='we',columnspan=20)
with jukeBox_dir/row 6 overriding inPut_dir/row 5
Therefore, in def input:
where you have:
entry.insert(0, inPut_dir)
You'll get the result in row 5 (jukebox_dir)

Python: What is the syntax for adding a command to a tkinter Listbox item?

below is my code for creating a tool that takes a file path, stores the value, and then opens the specific file path selected by the user.
Currently, I'm looking to take the user entry mypathEntry that is stored in the mypathList listbox after clicking the Save button and add a command to it. The command will open that selected file path. My current code returns an error message regarding mypathList.add_command(command=Open) stating that Listbox instance has no attribute 'add_command'.
What is the syntax for adding a command to a listbox item?
from Tkinter import *
import os
root = Tk()
def Save():
fp = mypathEntry.get()
scribe = open('filepath.txt', 'w')
scribe.write(fp)
mypathEntry.delete(0, 'end')
mypathList.insert(1, fp)
def Open():
path = fp
menu = Menu(root)
##root.config(menu=menu)
##subMenu = Menu(menu)
##menu.add_cascade(label="Filepaths", menu=subMenu)
##subMenu.add_command(command=Save)
mypathLabel = Label(root, text="Copy and Paste your filepath here:")
mypathEntry = Entry(root, bg="black", fg="white", relief=SUNKEN)
mypathSaveButton = Button(root, text="Save Path", bg="black", fg="white", command=Save)
mypathList = Listbox(root, bg="black", fg="white")
mypathList.add_command(command=Open)
mypathLabel.pack()
mypathEntry.pack()
mypathSaveButton.pack()
mypathList.pack()
root.mainloop()
According to this,
http://effbot.org/tkinterbook/listbox.htm
The listbox item does not have a command option. So what you need to do instead is to bind an event to it. Here is a complete working example.
from tkinter import *
import os
root = Tk()
class MainGui:
def __init__(self, master):
self.mypathLabel = Label(master, text="Copy and Paste your filepath here:")
self.mypathEntry = Entry(master, bg="black", fg="white", relief=SUNKEN)
self.mypathSaveButton = Button(master, text="Save Path", bg="black", fg="white", command=self.save_path)
self.mypathList = Listbox(master, bg="black", fg="white")
self.mypathLabel.pack()
self.mypathEntry.pack()
self.mypathSaveButton.pack()
self.mypathList.pack()
self.mypathList.bind("<Double-Button-1>", self.open_path)
def save_path(self):
fp = self.mypathEntry.get()
self.mypathEntry.delete(0, 'end')
self.mypathList.insert(1, fp)
def open_path(self, event):
list_item = self.mypathList.curselection()
fp = self.mypathList.get(list_item[0])
print(fp)
try:
with open(fp, 'r') as result:
print(result.read())
except Exception as e:
print(e)
MainGui(root)
root.mainloop()

Categories

Resources