OS.rename() not working with tkinter - python

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()

Related

How to set the text in tkinter?

I want to set the answer using the set() method without writing it in the text attribute in the Label and also I want to change the message without displaying the messages over each other.
I want the new message to appear and the one before it to disappear. I tried to use the set() and get() methods but it used to return its default value without using the value in the set() method and I don't know why.
from tkinter import *
from tkinter import messagebox
from PIL import ImageTk,Image
root= Tk()
root.title("Project")
root.geometry('500x600')
root.title('Choose Answer')
var = IntVar()
textt = StringVar()
print(textt.set('Clicked..........'))
def Result():
print(textt.set('You Clicked....................'))
if(var.get() == 1):
print(var.get())
print(textt)
textt.set('You Clicked')
resultText = Label(root, text=textt , fg='white',bg='gray', width=40)
resultText.place(x=100,y=200)
else:
textt.set('You did\'t Click')
resultText = Label(root, text=textt, fg='white',bg='grey', width=40)
resultText.place(x=100,y=200)
checkBox = Checkbutton(root, text='Did you Study Math', variable=var, bg='grey')
checkBox.place(x=50,y=50)
button = Button(root, text='Select', fg='white', bg='grey',font='sans-serif',command=Result)
button.place(x=50,y=100)
root.mainloop()
This should work:
from tkinter import *
root = Tk()
root.title("Project")
root.geometry('500x600')
root.title('Choose Answer')
var = IntVar()
textt = StringVar()
resultText = Label(root, textvariable=textt , fg='white',bg='gray', width=40)
resultText.place(x=100,y=200)
def Result():
print(var.get())
if var.get() == 1:
textt.set('You Clicked')
else:
textt.set('You didn\'t Click')
checkBox = Checkbutton(root, text='Did you Study Math', variable=var, bg='grey')
checkBox.place(x=50,y=50)
button = Button(root, text='Select', fg='white', bg='grey',font='sans-serif',command=Result)
button.place(x=50,y=100)
root.mainloop()
When you create resultText, instead of setting the text argument to textt, you need to set the textvariable argument to text. That way, the text of the variable is automatically changed when you change textt.
I removed all the lines where resultText was recreated and re-placed, and just created it once before defining Result(). Also, I removed from tkinter import messagebox, because you already import it when you call from tkinter import *. Just a note: wildcard imports are discouraged, so try to avoid using them in the future.

Problem at saving a file in certain route that I entry

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()

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)

Why is Tkinter Entry's get function returning nothing?

I'm trying to use an Entry field to get manual input, and then work with that data.
All sources I've found claim I should use the get() function, but I haven't found a simple working mini example yet, and I can't get it to work.
I hope someone can tel me what I'm doing wrong. Here's a mini file:
from tkinter import *
master = Tk()
Label(master, text="Input: ").grid(row=0, sticky=W)
entry = Entry(master)
entry.grid(row=0, column=1)
content = entry.get()
print(content) # does not work
mainloop()
This gives me an Entry field I can type in, but I can't do anything with the data once it's typed in.
I suspect my code doesn't work because initially, entry is empty. But then how do I access input data once it has been typed in?
It looks like you may be confused as to when commands are run. In your example, you are calling the get method before the GUI has a chance to be displayed on the screen (which happens after you call mainloop.
Try adding a button that calls the get method. This is much easier if you write your application as a class. For example:
import tkinter as tk
class SampleApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.entry = tk.Entry(self)
self.button = tk.Button(self, text="Get", command=self.on_button)
self.button.pack()
self.entry.pack()
def on_button(self):
print(self.entry.get())
app = SampleApp()
app.mainloop()
Run the program, type into the entry widget, then click on the button.
You could also use a StringVar variable, even if it's not strictly necessary:
v = StringVar()
e = Entry(master, textvariable=v)
e.pack()
v.set("a default value")
s = v.get()
For more information, see this page on effbot.org.
A simple example without classes:
from tkinter import *
master = Tk()
# Create this method before you create the entry
def return_entry(en):
"""Gets and prints the content of the entry"""
content = entry.get()
print(content)
Label(master, text="Input: ").grid(row=0, sticky=W)
entry = Entry(master)
entry.grid(row=0, column=1)
# Connect the entry with the return button
entry.bind('<Return>', return_entry)
mainloop()
*
master = Tk()
entryb1 = StringVar
Label(master, text="Input: ").grid(row=0, sticky=W)
Entry(master, textvariable=entryb1).grid(row=1, column=1)
b1 = Button(master, text="continue", command=print_content)
b1.grid(row=2, column=1)
def print_content():
global entryb1
content = entryb1.get()
print(content)
master.mainloop()
What you did wrong was not put it inside a Define function then you hadn't used the .get function with the textvariable you had set.
you need to put a textvariable in it, so you can use set() and get() method :
var=StringVar()
x= Entry (root,textvariable=var)
Most of the answers I found only showed how to do it with tkinter as tk. This was a problem for me as my program was 300 lines long with tons of other labels and buttons, and I would have had to change a lot of it.
Here's a way to do it without importing tkinter as tk or using StringVars. I modified the original mini program by:
making it a class
adding a button and an extra method.
This program opens up a tkinter window with an entry box and an "Enter" button. Clicking the Enter button prints whatever is in the entry box.
from tkinter import *
class mini():
def __init__(self):
master = Tk()
Label(master, text="Input: ").grid(row=0, sticky=W)
Button(master, text='Enter', command=self.get_content).grid(row=1)
self.entry = Entry(master)
self.entry.grid(row=0, column=1)
master.mainloop()
def get_content(self):
content = self.entry.get()
print(content)
m = mini()

Categories

Resources