I want to show a message box, but without the parent window behind it in Python. This is my code:
import Tkinter, tkFileDialog ,tkMessageBox
from fileManagerModule import fileManager
def load():
global myFile,flag,msg
flag=True
options = {}
options["title"] = "choose a text File"
options['initialdir'] = '~/'
fileName = tkFileDialog.askopenfilename(**options)
myFile = fileManager(fileName)
myText.delete("1.0", Tkinter.END)
try:
line = myFile.readFromFile()
myText.insert("1.0", line)
except:
msg=Tkinter.Tk()
msg=tkMessageBox.showerror("Error","please choose file to load")
screenshot
You can use the withdraw() function to remove the window being displayed in the background to just show the dialog box only.
try this:
import Tkinter, tkFileDialog ,tkMessageBox
from fileManagerModule import fileManager
def load():
global myFile,flag,msg
flag=True
options = {}
options["title"] = "choose a text File"
options['initialdir'] = '~/'
fileName = tkFileDialog.askopenfilename(**options)
myFile = fileManager(fileName)
myText.delete("1.0", Tkinter.END)
try:
line = myFile.readFromFile()
myText.insert("1.0", line)
except:
msg=Tkinter.Tk()
msg.withdraw()
msg=tkMessageBox.showerror("Error","please choose file to load")
Add the following to your code:
import Tkinter,tkMessageBox
.
.
at program initialisation add a global variable
msgWindow = None
at your code initialisation add the following lines:
.. before the very first call to tkMessageBox
def initialise():
global msgWindow
.
.
msgWindow = Tkinter.Tk()
msgWindow.withdraw()
in your code where you call tkMessageBox, just call
tkMessageBox the way you normally call it.
if not tkMessageBox.askyesno('What to do','Continue ?'):
.....
at any exit point where your program terminates, add
msgWindow.destroy()
That will do.
Related
This is my current code.
from tkinter import *
from tkinter import ttk, filedialog
from tkinter.filedialog import askopenfile
import os
def main():
path = open_file()
print(path)
# Create an instance of tkinter frame
win = Tk()
# Set the geometry of tkinter frame
win.geometry("700x350")
def open_file():
file = filedialog.askopenfile(mode='r', filetypes=[('PDF', '*.pdf')])
if file:
filepath = os.path.abspath(file.name)
quit()
print(filepath)
def quit():
win.destroy()
# Add a Label widget
label = Label(win, text="Click the Button to browse the Files", font=('Georgia 13'))
label.pack(pady=10)
# Create a Button
ttk.Button(win, text="Browse", command=open_file).pack(pady=20)
win.mainloop()
if __name__ == '__main__':
main()
I want to create a simple GUI to select a file and then use its path in other functions later on. In the current code the filepath prints out fine after the window closes in the open_file function, but it only works if the print statement is in the function. If I remove it from there and want to print it out(just to test) or use it further to pass it to other functions from main it doesn't seem to work. There is no error but it doesn't print anything either. Any idea?
The problem appears to be is wanting to return a value from a function called with a button. This is apparently not possible. The easiest solution I've found (without changing too much of your code structure) is to use a global variable for filepath. Now you can use it pretty much anywhere you want.
Also, I've removed path = open_file() from your main() function as it is redundant. The function is now called only when the button is pressed and not at every start of the program.
from tkinter import *
from tkinter import ttk, filedialog
from tkinter.filedialog import askopenfile
import os
def main():
print(filepath)
# Create an instance of tkinter frame
win = Tk()
# Set the geometry of tkinter frame
win.geometry("700x350")
def open_file():
file = filedialog.askopenfile(mode='r', filetypes=[('PDF', '*.pdf')])
if file:
global filepath
filepath = os.path.abspath(file.name)
quit()
def quit():
win.destroy()
# Add a Label widget
label = Label(win, text="Click the Button to browse the Files", font=('Georgia 13')) label.pack(pady=10)
# Create a Button
ttk.Button(win, text="Browse", command=open_file).pack(pady=20)
win.mainloop()
if __name__ == '__main__':
main()
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 need to load up a quiz that is in a separate python file when a button is pressed in one of the menus. I tried to use import, however it causes the other python file to run straight away, rather than only when the button is pressed, how would I fix this?
import FSMQuiz1
def selectTask():
screen7 = Toplevel(screen5)
screen7.geometry("600x450+686+254")
screen7.title("Select a task")
Label(screen7, text = "Please select a task...", font = ("Calbiri",14)).place(relx=0.25, rely=0.044, height=41, width=304)
Button(screen7, text = "Finite State Machines", command = FSMQuiz1).place(relx=0.15, rely=0.2, height=54, width=117)
what if you use the python build in function exec?
you can use this function to load a file:
def exec_file(file_name):
#open the file
with open('your/file.txt') as fh:
#read it
data = fh.read()
#execute it
exec(data)
You can use importlib to load python files.
from os import path
from importlib.util import module_from_spec, spec_from_file_location
spec = spec_from_file_location("module.name", path.join(PATH, 'file.py'))
module = module_from_spec(spec)
spec.loader.exec_module(module)
Try:
import FSMQuiz1
def selectTask():
screen7 = Toplevel(screen5)
screen7.geometry("600x450+686+254")
screen7.title("Select a task")
Label(screen7, text = "Please select a task...", font = ("Calbiri",14)).place(relx=0.25, rely=0.044, height=41, width=304)
Button(screen7, text = "Finite State Machines", command = lambda: FSMQuiz1).place(relx=0.15, rely=0.2, height=54, width=117)
Set the button command in a define, then use the command to call it, eample:
def CallButton():
import FSMQuiz1
def selectTask():
screen7 = Toplevel(screen5)
screen7.geometry("600x450+686+254")
screen7.title("Select a task")
Label(screen7, text = "Please select a task...", font = ("Calbiri",14)).place(relx=0.25, rely=0.044, height=41, width=304)
Button(screen7, text = "Finite State Machines", command = CallButton).place(relx=0.15, rely=0.2, height=54, width=117)
I'm running Tkinter to get a file path using the function filedialog.askopenfilename(). The program is getting the file path correctly but once I click "Open" on the file I want, the code destroy() does not destroy the GUI window that is open.
I've tried both the destroy() and the quit() functions, though I read that destroy() is preferred. I read that if I do root.destroy(), it is supposed to destroy the GUI that is open. What is happening is that, after the user picks a file, then clicks open, the finder window then becomes totally greyed out and unresponsive. I'm guessing this is the point at which we can execute a destroy, but it's not working for me.
I'm really not sure where I'm going wrong. Would really like to delete the Tkinter browser. My code does continue executing despite the browser being open, but it's unprofessional.
import tkinter
from tkinter import filedialog
import os
root = tkinter.Tk()
root.withdraw() #use to hide tkinter window
def search_for_file_path ():
currdir = os.getcwd()
tempdir = filedialog.askopenfilename(parent=root, initialdir=currdir, title='Please select a directory')
if len(tempdir) > 0:
print ("You chose: %s" % tempdir)
return tempdir
file_path_variable = search_for_file_path()
root = tkinter.Tk()
root.destroy()
print ("\nfile_path_variable = ", file_path_variable)
remove the second instance
import tkinter
from tkinter import filedialog
import os
root = tkinter.Tk()
root.withdraw() #use to hide tkinter window
def search_for_file_path ():
currdir = os.getcwd()
tempdir = filedialog.askopenfilename(parent=root, initialdir=currdir, title='Please select a directory')
if len(tempdir) > 0:
print ("You chose: %s" % tempdir)
return tempdir
file_path_variable = search_for_file_path()
# remove the second instance
root.destroy()
print ("\nfile_path_variable = ", file_path_variable)
If it were me than I would use root.mainloop() and then root.destroy(). There are other ways but I am not sure if they work.
Seem to have fixed the problem! When I execute the script from the terminal, instead of clicking "run" inside the python app, it works. I'm not sure why one works and not the other, but I'll take it.
This is for my assignment.
I was given a template like this... def_choosefile() :
import tkinter
from tkinter import filedialog
root_window = tkinter.Tk()
root_window.withdraw()
return filedialog.askopenfilename()
So if i get this correct, it'll prompt a dialog window, asking to select a file. And when a file is selected, the program is supposed to tell what files did it pick. Using these:
selected_file = choose_file()
print ("Selected file: {}".format (selected_file))
after that, how do i make the program read the files normally? Normally i would use:
infile = open('text')
infile.readline()
import tkinter
from tkinter import filedialog
root_window = tkinter.Tk()
root_window.withdraw()
def choose_file():
return filedialog.askopenfilename()
selected_file = choose_file()
with open (selected_file,'r') as readfile:
lines = readfile.read().splitlines()
for line in lines[0:2]:
print (line)