Problem at saving a file in certain route that I entry - python

I have a problem when I'm trying to autocreate a file when I introduce a route in an Entry. The thing is if the program asks you where to save it, it saves it perfectly, but I would like that my program firstly saves the file if I indicate a previous route in an Entry and ONLY ask me where I want to save it if I don't entry any specific route (which as I said, does it perfectly)
I'm new at Python and don't know what I'm doing wrong, don't know if the problem is that I'm linking wrongly the route in the code and it can't recognize where I'm asking to save it.
When I'm introducing an ID and a route, it gives this error:
PermissionError: [Errno 13] Permission denied: 'Desktop';
and when I'm ONLY introducing an ID (leaving route empty), it gives this error:
FileNotFoundError: [Errno 2] No such file or directory: ''
and what I want is that when I only introduce an ID, I'd like it to ask me where I want to save this file.
from tkinter import *
from tkinter import filedialog
window = Tk()
window.title("app")
idcheck = StringVar()
route = StringVar()
def function():
if route:
**idchecklist = open(route, "w")**
else:
idchecklist = filedialog.asksaveasfile(mode='w',defaultextension=".txt")
idchecklist.write(idcheck.get())
idchecklist.close()
Label(window, text="ID").grid(padx=10 ,pady=10, row=0, column=0)
Entry(window, textvariable=idcheck).grid(padx=5, row=0, column=1, sticky=E+W)
Label(window, text="Saving route").grid(padx=10 ,pady=10, row=1, column=0)
Entry(window, textvariable=route, width=50).grid(padx=5, row=1, column=1)#, sticky=E+W)
Button(window, text="Generate", command=function).grid(padx=10,pady=10,row=2,column=0,columnspan=2,sticky=E+W)
window.mainloop()
To finish, is there any way to save the route Entry I introduced just in case that I want to use the program more than once and not having to introduce this entry every time? It would be great.
Thank you so much.
ps. Sorry if I did some writing mistakes.

You shouldn't use route, but route.get() in your code.
route in your case is just a container for a string, a StringVar object, so the if considers it being True. route.get(), on the other hand, is a string, which is retrieved from the Entry. So, the final code could look similar to this:
from tkinter import *
from tkinter import filedialog
window = Tk()
window.title("app")
idcheck = StringVar()
route = StringVar()
def function():
if route.get():
idchecklist = open(route.get(), "w")
else:
idchecklist = filedialog.asksaveasfile(mode='w',defaultextension=".txt")
idchecklist.write(idcheck.get())
idchecklist.close()
Label(window, text="ID").grid(padx=10 ,pady=10, row=0, column=0)
Entry(window, textvariable=idcheck).grid(padx=5, row=0, column=1, sticky=E+W)
Label(window, text="Saving route").grid(padx=10 ,pady=10, row=1, column=0)
Entry(window, textvariable=route, width=50).grid(padx=5, row=1, column=1)#, sticky=E+W)
Button(window, text="Generate", command=function).grid(padx=10,pady=10,row=2,column=0,columnspan=2,sticky=E+W)
window.mainloop()
If I'm getting you correct (see comments), here's even better version:
from tkinter import *
from tkinter import filedialog
import os
# create window
window = Tk()
window.title("app")
# create some containers for inputs
idcheck = StringVar()
route = StringVar()
# create input entrys
Label(window, text="ID").grid(padx=10 ,pady=10, row=0, column=0)
Entry(window, textvariable=idcheck).grid(padx=5, row=0, column=1, sticky=E+W)
Label(window, text="Saving route").grid(padx=10 ,pady=10, row=1, column=0)
Entry(window, textvariable=route, width=50).grid(padx=5, row=1, column=1)#, sticky=E+W)
# Update function
def function():
if route.get(): # if route is not '' then use it else ask for it
idcheckpath = route.get()
else:
idcheckpath = filedialog.askdirectory()
route.set(idcheckpath)
# create and fill the file
idchecklist = open(idcheckpath+os.sep+idcheck.get()+'.txt', 'w')
idchecklist.write(idcheck.get())
idchecklist.close()
# generate new id:
alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
# get the old id and split it into a number and a string
old_id = idcheck.get()
if len(old_id) != 8:
old_id='000000AA'
letters = old_id[6:]
number = int(old_id[:6])
# check if the last letter is Z
if letters[1] == alphabet[-1]:
if letters[0] == alphabet[-1]: # if both letters are Z, update the number
letters = 'AA'
number += 1
else:
letters = alphabet[1+alphabet.find(letters[0])]+'A' # if only the last letter is Z, update both letters
else:
letters = letters[0]+alphabet[1+alphabet.find(letters[1])] # update the last letter
idcheck.set(str(number).zfill(6)+letters) # save a new id
Button(window, text="Generate", command=function).grid(padx=10,pady=10,row=2,column=0,columnspan=2,sticky=E+W)
window.mainloop()

Related

One of my variables is being printed but the other is not in tkinter Entry boxes

I'm trying to create a function in tkinter where I can print out what the user writes in a Entry box. I'm able to print out ask_an_entry_get, but when I try to print what_is_answer_entry_get
, I get nothing my empty spaces.
Please find out the problem here. Also I'm using the Entry widget, along with the get() function, to get input from the user.
def answer_quizmaker_score():
print(ask_an_entry_get)
print(what_is_answer_entry_get)
I made a lot of global variables so I could use them all around my code.
global what_is_answer_entry
what_is_answer_entry = Entry(root4)
what_is_answer_entry.pack()
I then used the get() function to retrieve what the user typed.
global what_is_answer_entry_get
what_is_answer_entry_get = what_is_answer_entry.get()
This is the exact process I did for both ask_an_entry_get and what_is_answer_entry_get. However for some reason only ask_an_entry_get is printed, while what_is_answer_entry_get is printing nothing in the console.
from tkinter import *
root = Tk()
root.geometry("500x500")
txt1 = StringVar()
txt2 = StringVar()
def txt_printer():
print(txt1.get())
print(txt2.get())
x = Entry(root, textvariable=txt1, width=20)
x.place(x=0, y=0)
y = Entry(root, textvariable=txt2, width=20)
y.place(x=0, y=50)
btn_print = Button(root, text="print", command=txt_printer)
btn_print.place(x=0, y=100)
# Or if you want to show the txt on window then:
def txt_on_window():
lb1 = Label(root, text=txt1.get())
lb1.place(x=0, y=200)
lb2 = Label(root, text=txt2.get())
lb2.place(x=0, y=235)
btn_print_on_window = Button(root, text="print on screen", command=txt_on_window)
btn_print_on_window.place(x=0, y=150)
root.mainloop()

How to correct the output from an entry box

When using the feeder button, the script for F runs through entirely through to the print before the 'master' box appears, then does not react to the inputs from the 'master' box. This results in the output being 0.0 kW because the input is a long decimals followed by an L, when what I, the user inputs is 8777
I have been roaming the internet for about a day now with no luck finding anything. I am very new to TK but have been trying to learn it.
def F():
master = tk.Tk()
tk.Label(master, text = 'Feeder Number: ').grid(row=0)
entry1 = tk.Entry(master)
entry1.grid(row=0, column=1)
button2 = tk.Button(master,
text=' Confirm',
command=entry1.get())
button2.pack()
button2.grid(row=0, column=2)
fn = entry1.pack()
print fn
feed = filtered['Feeder']==fn
feedfn = filtered[feed]
Cap = feedfn['AC Name Plate Capacity <= 10kw']
Cap = Cap.astype(float)
AcPv = Cap.sum()
print 'The total PV on this feeder is:', AcPv, 'kW'
root = tk.Tk()
frame = tk.Frame(root)
frame.pack()
button = tk.Button(frame,
text='Exit',
fg='red',
command=quit)
button.pack()
button.grid(row=1, column=1)
Fee = tk.Button(frame,
text='Feeder',
command=F)
Fee.pack()
Fee.grid(row=0, column=1)
root.mainloop()
Expected 27.702
Output 0.0
Given that I will not be posting the csv,
entry1/fn should be 8777
currently 'none'
UPDATE
I am now receiving an output of PY_VAR when printing fn, I understand that the code is running all the way through before taking an input. Any recommendations for how to take the input before the filters are run?
def F():
master = tk.Tk()
tk.Label(master, text = 'Feeder Number: ').grid(row=0)
entry1 = tk.Entry(master)
entry1.grid(row=0, column=1)
button2 = tk.Button(master,
text=' Confirm',
command=entry1.get())
button2.grid(row=0, column=2)
fn = tk.IntVar()
print fn
feed = filtered['Feeder']==fn
feedfn = filtered[feed]
Cap = feedfn['AC Name Plate Capacity <= 10kw']
Cap = Cap.astype(float)
AcPv = Cap.sum()
print 'The total PV on this feeder is:', AcPv, 'kW'
For those interested in the final code (Which worked for me):
def F():
master = tk.Tk()
tk.Label(master, text = 'Feeder Number: ').grid(row=0)
entry = tk.Entry(master)
entry.grid(row=0, column=1)
def pint():
data = entry.get()
master.destroy()
feed = filtered['Feeder']==data
feedfn = filtered[feed]
Cap = feedfn['AC Name Plate Capacity <= 10kw']
Cap = Cap.astype(float)
AcPv = Cap.sum()
fdf = tk.Tk()
tk.Label(fdf, text = AcPv).grid(row=0)
button4 = tk.Button(fdf,
text = ' Exit',
fg='red',
command=fdf.destroy)
button4.grid(row=1)
button2 = tk.Button(master,
text=' Confirm',
command = pint)
button2.grid(row=0, column=2)
button3 = tk.Button(master,
text = ' Exit',
fg='red',
command=master.destroy)
button3.grid(row=0, column=3)
master.mainloop()
There a few mistake in your code that lead to the different output you have received.
First, why is your code executing without showing the master box :
Your tkinter need a mainloop() call if you want a persistent window.
master.mainloop()
You did that right with your root, but your master lacks that mainloop. This line is what basically keeping your GUI alive and looping over it for changes until it is destroyed one way or another. You need to add this line after creating your widgets in order to be able to interact with the window. Anything written after this line (but still indented in the definition) will be executed when your window is closed, either manually or with the command :
master.destroy()
Next, although this will yield a working window, you can still interact with your root window while the master window is up, which can lead to problems if you are expecting variable from master. I suggest you read about the Toplevel widget which is made specifically for cases like yours. (http://effbot.org/tkinterbook/toplevel.htm) Alternatively, you could also use tkinter's tkSimpleDialog.askinteger or askfloat functions which seems perfect for your application.
Finally, the entry allows you to write text but how to access the text? you can use Entry1.get() to extract the content of the entry, or as you have started to to in your update, you can assign a tkinter variable to the entry. This variable will be updated as you change write strings or numbers in the entry. To bind the variable to your entry, you must state it in the entry's creation :
fn = tk.StringVar(value = '000')
entry1 = tk.Entry(master, textvariable = fn)
*Note, this will require your fn variable to be initialized before the entry. Also, you can initialize a value for that variable upon creation
the tkinter variable is an object which is why when you print it, you get PY_VAR. (the type of object) To access the value, you need to use the get() method :
print(fn.get())

Printing variables in tkinter GUI

This is my code:
import pandas as pd
from tkinter import *
master = Tk()
label1= Label(master, text='Department')
label1.grid(row=0, column=0)
textBox = Text(master, height=1, width=10)
textBox.grid(row=0, column=1)
def retrieve_input():
Department = textBox.get("1.0","end-1c")
fileread = pd.read_csv('50.csv', encoding='latin-1')
filevalue = fileread.loc[fileread['Customer'].str.contains(Department, na=False)]
def printSomething():
label = Label(master, textvariable=filevalue)
label.grid(row=3, column=1)
button1 = Button(master,text="Show Values", command=lambda: retrieve_input())
button1.grid(row=2, column=1)
mainloop( )
I have searched around Stack Overflow of how to do this, and was able to construct my code up until this point, However when I click the Show values button, nothing happens. I could find nowhere online that helped address this issue. Is there something fundamentally wrong with my code? Using Python 3.7
You define a nested printSomething function that would display something, but you never call that function.
This would fix that problem:
def retrieve_input():
Department = textBox.get("1.0","end-1c")
fileread = pd.read_csv('50.csv', encoding='latin-1')
filevalue = fileread.loc[fileread['Customer'].str.contains("Lam Dep", na=False)]
def printSomething():
label = Label(master, textvariable=filevalue)
label.grid(row=3, column=1)
printSomething()
But I'm not sure why you need the function in the first place; you can just do this:
def retrieve_input():
Department = textBox.get("1.0","end-1c")
fileread = pd.read_csv('50.csv', encoding='latin-1')
filevalue = fileread.loc[fileread['Customer'].str.contains("Lam Dep", na=False)]
label = Label(master, textvariable=filevalue)
label.grid(row=3, column=1)
But you have a second problem: You're trying to set the textvariable=filevalue, but that doesn't make any sense.
The textvariable has to be a tkinter.StringVar instance, not a plain old Python string. You can then set the StringVar to hold your string.
filevar = StringVar()
filevar.set(filevalue)
label = Label(master, textvariable=filevar)
label.grid(row=3, column=1)
… or just pass the text in directly, without a tkinter variable:
label = Label(master, text=filevalue)
label.grid(row=3, column=1)
There's still one more problem: Every time you call retrieveInput, it's going to create a new Label and grid it in front of whatever used to be there, but you never delete the old ones. So if you press the button over and over again, there will be a whole stack of invisible widgets just wasting resources.
It probably makes more sense to move the label creation to the global scope, just like the text box and the other label, and replace its text in this function, instead of creating a new label each time.
Using a StringVar is the simplest way to do this:
# ...
textBox = Text(master, height=1, width=10)
textBox.grid(row=0, column=1)
fileVar = StringVar()
fileLabel = Label(master, textvariable=fileVar)
fileLabel.grid(row=3, column=1)
def retrieve_input():
Department = textBox.get("1.0","end-1c")
fileread = pd.read_csv('50.csv', encoding='latin-1')
filevalue = fileread.loc[fileread['Customer'].str.contains("Lam Dep", na=False)]
fileVar.set(filevalue)
# ...
You may have other bugs in your code, but I think if you fix these three, you'll at least be pretty close to everything working.
Considering you are running Python 3.7, as you said, the following code will solve your problem:
import pandas as pd
from tkinter import *
master = Tk()
label1= Label(master, text='Department')
label1.grid(row=0, column=0)
textBox = Text(master, height=1, width=10)
textBox.grid(row=0, column=1)
def retrieve_input():
global text
department = textBox.get("1.0","end-1c")
fileread = pd.read_csv('50.csv', encoding='latin-1')
filevalue = fileread.loc[fileread['Customer'].str.contains("Lam Dep", na=False)]
text.set(filevalue)
button1 = Button(master,text="Show Values", command=retrieve_input)
button1.grid(row=2, column=1)
text = StringVar()
label = Label(master, textvariable=text)
label.grid(row=0, column=1)
mainloop()
You are facing these problems:
You are defining an inner function printSomething which is never called.
Even if you were calling printSomething you are going to create a new Label every time you press button1.
In this as, you don't need to use lambda to pass the callback that will be executed, you can simply pass command=retrieve_input
The simplest solution might be to define a StringVar (text) which is going to be associated with a Label (label), and when you press the button button1 you update call the method set on that variable text.

Python 2.7: Adding new items to Tkinter listbox without adding existing values

I am writing a simple bulk file utility. I have two listboxes in the GUI. Listbox1 contains a list of files that exist in whichever directory the user selects. The user can then add selected items in listbox1, to listbox2. Currently this allows duplicate items to be added. I would like to figure out how to check if selected items already exist in listbox2, and only add items that aren't already present.
Here is my code:
from Tkinter import *
import Tkinter, Tkconstants, tkFileDialog, tkMessageBox
import os, sys
class FileZap():
def __init__(self, root):
def getDir():
dir = tkFileDialog.askdirectory(initialdir="C:/")
self.user1.delete(0,END)
self.user1.insert(0,dir)
files = (file for file in os.listdir(dir)
if os.path.isfile(os.path.join(dir, file)))
for file in files:
self.listbox1.insert(0,file)
def selectAdd():
selection1 = self.listbox1.curselection()
for i in selection1:
selectedFiles = self.listbox1.get(i)
self.listbox2.insert(0, selectedFiles)
root.title("Test_App 1.0")
root.geometry("860x450")
self.listbox1 = Listbox(root, width=50, selectmode="multiple")
self.listbox1.grid(row=2, column=2)
self.scrollbar = Scrollbar(orient=VERTICAL, command=self.listbox1.yview)
self.listbox1.config(yscrollcommand=self.scrollbar.set)
self.scrollbar.grid(row=2, column=3, sticky="ns")
self.listbox2 = Listbox(root, width=50)
self.listbox2.grid(row=2, column=4)
self.label1 = Label(root, text="Select a folder: ")
self.label1.grid(row=1, column=1)
self.user1 = Entry(root, width="50")
self.user1.grid(row=1, column=2)
self.browse = Button(root, text="Browse", command=getDir)
self.browse.grid(row=1, column=3)
self.button2 = Button(root, text="Add to Selection", command=selectAdd)
self.button2.grid(row=3, column=3)
self.quit = Button(root, text="Exit", command=root.quit)
self.quit.grid(row=8, column=4)
root = Tkinter.Tk()
file_zap = FileZap(root)
root.mainloop()
In the above code the function selectAdd() performs the item manipulation. I was hoping to do this by adding another for loop within the function that returns the values in listbox2, and adding items if not in listbox2. However I can only seem to return selected values using .get, I can't figure out how to select all values. Also I'm not sure that this is even the best way to do this. Any help would be much appreciated!
How about just getting all values currently in the second listbox with listbox2.get(0,END) and if there are no duplicates add the selectedFiles:
def selectAdd():
selection1 = self.listbox1.curselection()
for i in selection1:
selectedFiles = self.listbox1.get(i)
list2files = self.listbox2.get(0, END)
if selectedFiles not in list2files:
self.listbox2.insert(0, selectedFiles)

OS.rename() not working with tkinter

Folks I'm trying to make a tool which gets user path and file name in one entry and new file name with path in another entry, My aim is to use os.rename(oldname, newname) to rename the given file, but its throwing me some error.
My code
from tkinter import *
import os
def Rename_Function(*args):
os.rename(oldname2,newname)
oldname.set(oldname)#"Renamed Successfully !!! ")
root = Tk()
root.title("MyPython App")
root.geometry("250x250+100+50")
oldname = StringVar()
oldname2= StringVar()
newname= StringVar()
Title1 = Label(root,text="FileName (with path):")
Title1.grid(row=0, column=0)
Oldfilename = Entry(root, textvariable=oldname2)
Oldfilename.grid(row=0, column=1)
Title2 = Label(root, text="New Filename:")
Title2.grid(row=1, column=0)
Newfilename = Entry(root, textvariable=newname)
Newfilename.grid(row=1, column=1)
RenameButton = Button(root, text="RENAME MY FILE", command=Rename_Function)
RenameButton.grid(row=3,columnspan=2, sticky="NWES")
FinalOutput = Label(textvariable=oldname)
FinalOutput.grid(row=4, columnspan=2, sticky = "NWES")
root.mainloop()
I'm getting the above error when I click the button,
Can someone guide me how to make it work.
I have a doubt that os.rename() function should be accessed in some other way since its another module's function. Since I'm learner I don't have any clue how to use them effeciently. Please guide me and explain me so that I would understand this concept better.
To expand upon what #SuperSaiyan said in the comment(s).
You are using a StringVar, which has the method .get() available to it. When you pass the variable which is set to this stringvar you are just passing the reference to this object. You need to actually use the .get() method to get the string.
e.g. - oldname2.get()
Also, for selecting the path you could just use a filedialog, and use os.path.splitext to get the base path + entry in the renaming widget to use as the second parameter with os.rename
You are using StringVar, whereas rename needs Strings. Use oldname.get():
import tkinter as tk
import os
def rename(oldname, oldname2, newname):
os.rename(oldname2.get(),newname.get())
oldname.set("Renamed Successfully !!! ")
def main():
root = tk.Tk()
root.title("MyPython App")
root.geometry("250x250+100+50")
oldname = tk.StringVar()
oldname2= tk.StringVar()
newname= tk.StringVar()
tk.Label(root, text="FileName (with path):").grid(row=0, column=0)
tk.Entry(root, textvariable=oldname2).grid(row=0, column=1)
tk.Label(root, text="New Filename:").grid(row=1, column=0)
tk.Entry(root, textvariable=newname).grid(row=1, column=1)
tk.Button(root, text="RENAME MY FILE", command=lambda: rename(oldname, oldname2, newname)).grid(row=3,columnspan=2, sticky="NWES")
tk.Label(textvariable=oldname).grid(row=4, columnspan=2, sticky = "NWES")
root.mainloop()
if __name__ == '__main__':
main()

Categories

Resources