I'm doing a python course and I'm learning to use tkinter here, and as part of the course they send me to make a text editor (a notepad), and I'm defining the functions of the menubar, but in the open one at the time of opening a file (obviously txt) gives me this error, could someone please help me, anyway... Thanks in advance.
from tkinter import *
from tkinter import filedialog as FileDialog
from io import open
rute = ""
def new():
global rute
message.set("New File")
rute = ""
text.delete(1.0, "end")
root.tittle(rute + " - MEditor")
def open():
global rute
message.set("Open File")
rute = FileDialog.askopenfilename(
initialdir='.',
filetype=( ("Text Files", "*.txt"), ),
title="Open a text file" )
if rute != "":
file = open(rute,'r')
content = file.read()
text.delete(1.0,'end')
text.insert('insert', content)
file.close()
root.tittle(rute + " - MEditor")
def save():
message.set("Save File")
def save_as():
message.set("Save File As...")
root = Tk()
root.title("MEditor")
menubar = Menu(root)
filemenu = Menu(menubar, tearoff=0)
filemenu.add_command(label="New",command=new)
filemenu.add_command(label="Open",command=open)
filemenu.add_command(label="Save",command=save)
filemenu.add_command(label="Save As",command=save_as)
filemenu.add_separator()
filemenu.add_command(label="Exit", command=root.quit)
menubar.add_cascade(menu=filemenu, label="File")
text = Text(root)
text.pack(fill='both', expand=1)
text.config(bd=0, padx=6, pady=4, font=("Consolas",12))
message = StringVar()
message.set("Welcome to MEditor!")
monitor = Label(root, textvar=message, justify='left')
monitor.pack(side='left')
root.config(menu=menubar)
root.mainloop()
throws me this error
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\anaconda3\envs\spyder-cf\lib\tkinter\__init__.py", line 1921, in __call__
return self.func(*args)
File "C:\Users\luisc\Desktop\CursoPython\Fase 4 - Temas avanzados\Tema 13 - Interfaces graficas con tkinter\editor.py", line 24, in open
file = open(rute,'r')
TypeError: open() takes 0 positional arguments but 2 were given
It should be said that I used anaconda for the jupyter notebook but to write scripts I am now using VSCode.
You named your own function open, shadowing the definition of the built-in open with a global scope definition (global scope names are always found before built-in names, you only find the latter if the former doesn't exist). Don't name-shadow built-ins, it only leads to pain.
Change:
def open():
to some other name and change all the places that call it to match.
A list of the built-ins can be found in the docs here:
https://docs.python.org/3/library/functions.html
Related
Ive rewritten this for more context, in a logical order this is what i want the program to do
1 by pressing open file it needs to open a specified file and put it into the text widget (done)
2 by pressing the extract file it needs to extract something from a specified subtree(in an xml file)
3 export the extracted data to a text file
but lets go back to point nr 2 as i have not yet written the extractor(easy part) first i need to refference a file i want to edit, and that is where i run into my problem. inside extract it cant acess vars in openfile and i dont want to reopen the file again.
from tkinter import *
from tkinter import ttk
from tkinter import filedialog
import tkinter as tk
interface = tk.Tk()
interface.geometry("500x500")
interface.title("Text display")
def openfile():
filename = filedialog.askopenfilename()
print(filename)
file = open(filename)
txt = file.read()
print(txt)
T = tk.Text(interface, height=10, width=50)
T.insert(tk.END, txt)
T.grid(column=1, row=2)
return txt
def extract():
print(txt)
button = ttk.Button(interface, text="Open text File", command=openfile) # <------
button.grid(column=1, row=1)
buttonex = ttk.Button(interface, text="Extract subtitles", command=extract) # <------
buttonex.grid(column=2, row=1)
interface.mainloop()
NameError: name 'txt' is not defined (when i press extract)
As the edit of the initial questions shows that a GUI is planned I would suggest to move your TK widgets into an interface class as in the tkinter documentation. Further, if you plan to do more complex manipulations you should make an own class to hold your data resp. manipulate it.
import tkinter as tk
class App(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.pack()
self.create_widgets()
def create_widgets(self):
# Create your buttons and connect them to the methods
self.button_load = tk.Button(self)
self.button_load["command"] = self.loadTextFromFile()
self.button_load["text"] = "Load Data"
self.button_load.gird(column=1, row=1)
self.buttonex = tk.Button(self)
self.buttonex["text"] = "Extract subtitles"
self.buttonex["command"] = self.extract()
self.buttonex.grid(column=2, row=1)
# Create the text widget
self.text_widget = tk.Text(self, height=10, width=50)
self.text_widget.grid(column=1, row=2)
def loadTextFromFile(self):
filename = filedialog.askopenfilename()
print(filename)
try:
file = open(filename)
txt = file.read()
file.close()
self.text_widget.insert(tk.END, txt)
except Exception:
# If anything went wrong, close the file before reraising
file.close()
raise
def extract(self):
# Now you have access to self.text_widget and it holds your read in text
do_something(self.text_widget)
# Maybe at the following functions to make your file importable without directly executing it. Could come in handy later on.
def run():
# create the application
myapp = App()
#
# here are method calls to the window manager class
#
myapp.master.title("My Do-Nothing Application")
myapp.master.maxsize(1000, 400)
# start the program
myapp.mainloop()
if __name__ == '__main__':
run()
Have a look at the tkinter documentation for further examples: https://docs.python.org/3/library/tkinter.html
The additional if clause checks if your module is the main module and executes the run function. This defines an entry point if you directly run your module and prevents functions from execution at import time if you intend to import the module into another module. A more detailed explanation can be found here:
What does if __name__ == "__main__": do?
---------- Old Answer --------------
As pointed out in the comment you need to somehow return your local variables back to the calling function in order to be able to use them somewhere else. This could be achieved by a simple return statement:
def openfile():
""" It is the responsibility of the caller to close the return value """
filename = filedialog.askopenfilename()
print(filename)
try:
file = open(filename)
txt = file.read()
T = tk.Text(interface, height=10, width=50)
T.insert(tk.END, txt)
T.grid(column=1, row=2)
return file
except Exception:
# If anything went wrong, close the file before reraising
file.close()
raise
would for example return the open fileid for further manipulation. E.g.:
def extract():
with openfile() as file:
txtex = file.read()
print (txtex)
If your goal is howeer, to manipulate the file content and read it later you would need to save your manipulations back into the file otherwise your second read would not see the changes. Dont forget to close your file again.
I changed three lines where I believe to have come across typos:
From: self.button_load["command"] = self.loadTextFromFile() to: self.button_load["command"] = self.loadTextFromFile
From: self.button_load.gird(column=1, row=1) to: self.button_load.grid(column=1, row=1)
From: self.buttonex["command"] = self.extract() to: self.buttonex["command"] = self.extract
Thank you for this example!
I'm working for the first time on coding a Browse button for a program in Python3. I've been searching the internet and this site, and even python standard library.
I have found sample code and very superficial explanations of things, but I haven't been able to find anything that addresses the problem I'm having directly, or a good enough explanation so I can customize code to my needs.
Here is the relevant snippet:
Button(self, text = "Browse", command = self.load_file, width = 10)\
.grid(row = 1, column = 0, sticky = W) .....
def load_file(self):
filename = filedialog.askopenfilename(filetypes = (("Template files", "*.tplate")
,("HTML files", "*.html;*.htm")
,("All files", "*.*") ))
if filename:
try:
self.settings["template"].set(filename)
except:
messagebox.showerror("Open Source File", "Failed to read file \n'%s'"%filename)
return
The method is a hybrid of some code I found along the way with my own customizations. It seems like I finally got it to work (kinda), though its not exactly how I need it.
I get this error when I activate the 'Browse' button: NameError: global name 'filedialog' is not defined.
I've found fairly similar issues along the way but all the solutions suggested I have covered. I went into the 'filedialog' help section of IDLE but didn't glean anything from there either.
Would someone mind providing a break down and a little guidance on this; none of my books address it specifically, and I've checked all the solutions provided to others—I'm lost.
The exception you get is telling you filedialog is not in your namespace.
filedialog (and btw messagebox) is a tkinter module, so it is not imported just with from tkinter import *
>>> from tkinter import *
>>> filedialog
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
NameError: name 'filedialog' is not defined
>>>
you should use for example:
>>> from tkinter import filedialog
>>> filedialog
<module 'tkinter.filedialog' from 'C:\Python32\lib\tkinter\filedialog.py'>
>>>
or
>>> import tkinter.filedialog as fdialog
or
>>> from tkinter.filedialog import askopenfilename
So this would do for your browse button:
from tkinter import *
from tkinter.filedialog import askopenfilename
from tkinter.messagebox import showerror
class MyFrame(Frame):
def __init__(self):
Frame.__init__(self)
self.master.title("Example")
self.master.rowconfigure(5, weight=1)
self.master.columnconfigure(5, weight=1)
self.grid(sticky=W+E+N+S)
self.button = Button(self, text="Browse", command=self.load_file, width=10)
self.button.grid(row=1, column=0, sticky=W)
def load_file(self):
fname = askopenfilename(filetypes=(("Template files", "*.tplate"),
("HTML files", "*.html;*.htm"),
("All files", "*.*") ))
if fname:
try:
print("""here it comes: self.settings["template"].set(fname)""")
except: # <- naked except is a bad idea
showerror("Open Source File", "Failed to read file\n'%s'" % fname)
return
if __name__ == "__main__":
MyFrame().mainloop()
I had to specify individual commands first and then use the * to bring all in command.
from tkinter import filedialog
from tkinter import *
Did you try adding the self prefix to the fileName and replacing the method above the Button ? With the self, it becomes visible between methods.
...
def load_file(self):
self.fileName = filedialog.askopenfilename(filetypes = (("Template files", "*.tplate")
,("HTML files", "*.html;*.htm")
,("All files", "*.*") ))
...
Tkinter is actually a python package, or a folder of python files. Check python source to find it. "tkinter.filedialog" is part of "tkinter.messagebox" Try "from tkinter.messagebox import filedialog" to get filedialog [python 3.7].
I'm trying to show the filepath of an accessed file in an 'Entry' box in Tkinter. Because of the requirements of this task I have to define all the functions in one file, and all the Tkinter fields in another and import the functions into the Tkinter file.
I tried putting all the code in a single file to see if that was causing any issues, and it worked fine. The problem is the task requires that I use seperate .py files.
def open_file():
filePath = askopenfilename()
with open(filePath, 'rU') as anotherFile:
inputString = anotherFile.read()
filePathEntry.delete(0, END)
filePathEntry.insert(0, filePath)
And in the other file:
from AT3_Functions_v2 import *
main = Tk()
main.geometry("600x400")
openfile = Button(main, text="Open Scoresheet", command=open_file).grid(row=0, column=0)
filePathEntry = Entry(main)
filePathEntry.grid(row=0, column=1)
mainloop()
When I put both segments of code in a single file it works flawlessly, however when I seperate it again it gives me the error:
NameError: global name 'filePathEntry' is not defined
When you place all your code in one single file then your open_file function can find filePathEntry variable. But when you split the code in two script then open_file can not find filePathEntry because it is in different file.
To solve this then you need to pass an argument in your open_file function using lambda function then place pass filePathEntry variable from another file. I have done for you.
script_one.py
from tkinter import *
from script_two to import *
main = Tk()
main.geometry("600x400")
filePathEntry = Entry(main)
filePathEntry.grid(row=0, column=1)
openfile = Button(main, text="Open Scoresheet", command=lambda: (open_file(filePathEntry))).grid(row=0, column=0) # Passing arugument to open_file function which is in script_two.py
mainloop()
script_two.py
from tkinter import *
from tkinter import filedialog
def open_file(entry_box): # Passing argument to access filePathEntry variable from script_one.py
filePath = filedialog.askopenfilename()
with open(filePath, 'rU') as anotherFile:
inputString = anotherFile.read()
entry_box.delete(0, END)
entry_box.insert(0, filePath)
Im trying to use tkinter to open a file dialog, once this file dialogue is open how do i get the file object that is returned by the function. As in how do i access it in main?
basically how do i handle return values by functions that are invoked by command
import sys
import Tkinter
from tkFileDialog import askopenfilename
#import tkMessageBox
def quit_handler():
print "program is quitting!"
sys.exit(0)
def open_file_handler():
file= askopenfilename()
print file
return file
main_window = Tkinter.Tk()
open_file = Tkinter.Button(main_window, command=open_file_handler, padx=100, text="OPEN FILE")
open_file.pack()
quit_button = Tkinter.Button(main_window, command=quit_handler, padx=100, text="QUIT")
quit_button.pack()
main_window.mainloop()
Instead of returning the file variable, just handle it there (I also renamed the file variable so you do not override the built-in class):
def open_file_handler():
filePath= askopenfilename() # don't override the built-in file class
print filePath
# do whatever with the file here
Alternatively, you can simply link the button to another function, and handle it there:
def open_file_handler():
filePath = askopenfilename()
print filePath
return filePath
def handle_file():
filePath = open_file_handler()
# handle the file
Then, in the button:
open_file = Tkinter.Button(main_window, command=handle_file, padx=100, text="OPEN FILE")
open_file.pack()
the easiest way I can think of is to make a StringVar
file_var = Tkinter.StringVar(main_window, name='file_var')
change your callback command using lambda to pass the StringVar to your callback
command = lambda: open_file_handler(file_var)
then in your callback, set the StringVar to file
def open_file_handler(file_var):
file_name = askopenfilename()
print file_name
#return file_name
file_var.set(file_name)
Then in your button use command instead of open_file_handler
open_file = Tkinter.Button(main_window, command=command,
padx=100, text="OPEN FILE")
open_file.pack()
Then you can retrieve the file using
file_name = file_var.get()
I'm working for the first time on coding a Browse button for a program in Python3. I've been searching the internet and this site, and even python standard library.
I have found sample code and very superficial explanations of things, but I haven't been able to find anything that addresses the problem I'm having directly, or a good enough explanation so I can customize code to my needs.
Here is the relevant snippet:
Button(self, text = "Browse", command = self.load_file, width = 10)\
.grid(row = 1, column = 0, sticky = W) .....
def load_file(self):
filename = filedialog.askopenfilename(filetypes = (("Template files", "*.tplate")
,("HTML files", "*.html;*.htm")
,("All files", "*.*") ))
if filename:
try:
self.settings["template"].set(filename)
except:
messagebox.showerror("Open Source File", "Failed to read file \n'%s'"%filename)
return
The method is a hybrid of some code I found along the way with my own customizations. It seems like I finally got it to work (kinda), though its not exactly how I need it.
I get this error when I activate the 'Browse' button: NameError: global name 'filedialog' is not defined.
I've found fairly similar issues along the way but all the solutions suggested I have covered. I went into the 'filedialog' help section of IDLE but didn't glean anything from there either.
Would someone mind providing a break down and a little guidance on this; none of my books address it specifically, and I've checked all the solutions provided to others—I'm lost.
The exception you get is telling you filedialog is not in your namespace.
filedialog (and btw messagebox) is a tkinter module, so it is not imported just with from tkinter import *
>>> from tkinter import *
>>> filedialog
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
NameError: name 'filedialog' is not defined
>>>
you should use for example:
>>> from tkinter import filedialog
>>> filedialog
<module 'tkinter.filedialog' from 'C:\Python32\lib\tkinter\filedialog.py'>
>>>
or
>>> import tkinter.filedialog as fdialog
or
>>> from tkinter.filedialog import askopenfilename
So this would do for your browse button:
from tkinter import *
from tkinter.filedialog import askopenfilename
from tkinter.messagebox import showerror
class MyFrame(Frame):
def __init__(self):
Frame.__init__(self)
self.master.title("Example")
self.master.rowconfigure(5, weight=1)
self.master.columnconfigure(5, weight=1)
self.grid(sticky=W+E+N+S)
self.button = Button(self, text="Browse", command=self.load_file, width=10)
self.button.grid(row=1, column=0, sticky=W)
def load_file(self):
fname = askopenfilename(filetypes=(("Template files", "*.tplate"),
("HTML files", "*.html;*.htm"),
("All files", "*.*") ))
if fname:
try:
print("""here it comes: self.settings["template"].set(fname)""")
except: # <- naked except is a bad idea
showerror("Open Source File", "Failed to read file\n'%s'" % fname)
return
if __name__ == "__main__":
MyFrame().mainloop()
I had to specify individual commands first and then use the * to bring all in command.
from tkinter import filedialog
from tkinter import *
Did you try adding the self prefix to the fileName and replacing the method above the Button ? With the self, it becomes visible between methods.
...
def load_file(self):
self.fileName = filedialog.askopenfilename(filetypes = (("Template files", "*.tplate")
,("HTML files", "*.html;*.htm")
,("All files", "*.*") ))
...
Tkinter is actually a python package, or a folder of python files. Check python source to find it. "tkinter.filedialog" is part of "tkinter.messagebox" Try "from tkinter.messagebox import filedialog" to get filedialog [python 3.7].