Tkinter doesn't stop execution even after closing the window - python

In this code I am displaying a window with a label and two buttons, the user can read the file path currently in use in the label and decide if he wants to change it or continue with the buttons.
If he wants to change the path then I change the value inside the textvariable inside the label. The issue is when I do this for example 3 times, then I have to kill the program manually pressing CTRL + C 3 times. If I do it once then I only need to do it once, like there is something preventing the program to terminate. Thanks for the help.
def select_file():
#OPEN TKINTER DIALOG LETTING ME TO CHOOSE A FILE AND RETURNS ITS PATH.
tkinter.Tk().withdraw() # prevents an empty tkinter window from appearing
folder_path = filedialog.askopenfilename()
return folder_path
def change_file():
file_path = select_file()
with open(os.path.expanduser('~/Documents/Squad Generator/excel_file_path.txt'), 'w') as f:
f.write(file_path)
#WRITES THE FILE PATH IN THE VARIABLE AND CHANGES THE LABEL
var.set(file_path)
def homepage():
app.geometry("450x200")
app.title("Squad Generator")
label_1 = tkinter.Label(master=app, justify=tkinter.LEFT,textvariable=var, font =
("JetBrains Mono", 15))
label_1.grid(row=0, column=0, columnspan=2, padx=20, pady=(20, 0), sticky="nsew")
button1 = tkinter.Button(master=app, text="Continua", command=main)
button1.grid(row=1, column=0, padx=20, pady=20, sticky="ew")
#BUTTON CAUSING THE ISSUE.
button2 = tkinter.Button(master=app, command=change_file, text="Cambia file")
button2.grid(row=1, column=1, padx=0, pady=20, sticky="ew")
#CREATING APP MAINLOOP
app.mainloop()
if __name__ == '__main__':
app = tkinter.Tk()
var = tkinter.StringVar(None, check_path_file())
homepage()

I've reorganized your application a bit. I've wrapped everything in a basic class named App which serves as the root of your application. This should work as expected and keep everything contained within a single instance of Tk.
import tkinter
from tkinter.filedialog import askopenfilename
class App(tkinter.Tk): # the App class inherits from Tk
def __init__(self):
super().__init__() # initialize Tk
self.geometry("450x200")
self.title("Squad Generator")
self.label_var=tkinter.StringVar(self, 'Select a file path')
self.label_1 = tkinter.Label(
master=self,
justify=tkinter.LEFT,
textvariable=self.label_var,
font=("JetBrains Mono", 15)
)
self.label_1.grid(row=0, column=0, columnspan=2, padx=20, pady=(20, 0), sticky="nsew")
self.button1 = tkinter.Button(master=self, text="Continua", command=main)
self.button1.grid(row=1, column=0, padx=20, pady=20, sticky="ew")
self.button2 = tkinter.Button(
master=self,
command=self.change_file,
text="Cambia file"
)
self.button2.grid(row=1, column=1, padx=0, pady=20, sticky="ew")
self.change_file() # call this function when the app starts
def change_file(self):
file_path = askopenfilename()
if file_path: # if a file is selected and not cancelled by the user
input_file = '~/Documents/Squad Generator/excel_file_path.txt'
with open(os.path.expanduser(input_file), 'w') as f:
f.write(file_path) # write out 'file_path' to the 'input_file'
#WRITES THE FILE PATH IN THE VARIABLE AND CHANGES THE LABEL
self.label_var.set(file_path)
else:
self.label_var.set('Select a file path') # fallback text if user cancels
if __name__ == '__main__':
app = App() # instantiate your App class
app.mainloop() # run the app
If you're not familiar with classes, the word self here can be confusing. All you need to know is that self refers to the App class. So any widgets you define within that class, like button1 have self as their master - i.e., they are children of the App class!
Also, any methods you define within the class (like change_file(self)) will be callable within the class via self.change_file, and will have access to any variables in the class, like self.label_var!

From what I see you just did
app.destroy()
But you actually need to do
app.master.destroy()
With the first line you're just destroying the current frame, not the the top level container.

Related

How do I correctly split my Tkinter app into multiple files?

I have a Tkinter GUI app, which has 2 parts that I want to split:
UI
Functions
Currently, everything is in one main.py file and inside of it the app is inside of a Class. To make things easier for me to learn, I slimmed down my app into this:
import tkinter as tk
import customtkinter
customtkinter.set_appearance_mode("Dark")
customtkinter.set_default_color_theme("blue")
# Custom Tkinter
class App(customtkinter.CTk):
def __init__(self):
super().__init__()
# configure window
self.title("Test app")
self.geometry(f"{1210}x{700}")
# Left frame
self.left_menu_frame = customtkinter.CTkFrame(master=self, width=300)
self.left_menu_frame.grid(row=1, column=0, padx=5, pady=5, sticky="news")
self.combobox_var = customtkinter.StringVar()
self.templates_list_cb = customtkinter.CTkComboBox(master=self.left_menu_frame, variable=self.combobox_var, values=['test1', 'test2'], command=self.insert_text)
self.templates_list_cb.grid(row=3, column=0, padx=5, pady=5)
# Right frame (Tab View)
self.tabView = customtkinter.CTkTabview(self, height=600, width=1025)
self.tabView.add("Text")
self.tabView.add("HTML")
self.tabView.grid(row=1, column=1, padx=5, pady=5, sticky="news")
self.tabView.tab("Text").grid_columnconfigure(0, weight=1)
self.tabView.tab("HTML").grid_columnconfigure(0, weight=1)
self.template_text = customtkinter.CTkTextbox(master=self.tabView.tab('Text'))
self.template_text.pack(expand=True, fill='both')
self.template_text_html = customtkinter.CTkTextbox(master=self.tabView.tab('HTML'))
self.template_text_html.pack(expand=True, fill='both')
def insert_text(self, *args):
self.template_text.delete("0.0", customtkinter.END)
self.template_text_html.delete("0.0", customtkinter.END)
self.template_text.insert("0.0", "this is a test")
self.template_text_html.insert("0.0", "this is also a test")
if __name__ == "__main__":
app = App()
app.mainloop()
Running the above code results in this app:
My real app looks pretty much the same, except it has more UI lines and functions, all inside this App class.
I want to split the code into files, as I read it's best practice. To my understanding, something like this should work (not sure about the naming):
- /
-- main.py
-- functions.py
-- ui.py
-- assets/
---- icon.png
If I go with that, I got the following files:
main.py
if __name__ == "__main__":
app = App()
app.mainloop()
functions.py
import ui
import customtkinter
app = ui.App()
def insert_text(app, *args):
app.template_text.delete("0.0", customtkinter.END)
app.template_text_html.delete("0.0", customtkinter.END)
app.template_text.insert("0.0", "this is a test")
app.template_text_html.insert("0.0", "this is also a test")
ui.py
import tkinter as tk
import customtkinter
import functions as f
customtkinter.set_appearance_mode("Dark")
customtkinter.set_default_color_theme("blue")
class App(customtkinter.CTk):
def __init__(self):
super().__init__()
# configure window
self.title("Test app")
self.geometry(f"{1210}x{700}")
# Left frame
self.left_menu_frame = customtkinter.CTkFrame(master=self, width=300)
self.left_menu_frame.grid(row=1, column=0, padx=5, pady=5, sticky="news")
self.combobox_var = customtkinter.StringVar()
self.templates_list_cb = customtkinter.CTkComboBox(master=self.left_menu_frame, variable=self.combobox_var, values=['test1', 'test2'], command=f.insert_text)
self.templates_list_cb.grid(row=3, column=0, padx=5, pady=5)
# Right frame (Tab View)
self.tabView = customtkinter.CTkTabview(self, height=600, width=1025)
self.tabView.add("Text")
self.tabView.add("HTML")
self.tabView.grid(row=1, column=1, padx=5, pady=5, sticky="news")
self.tabView.tab("Text").grid_columnconfigure(0, weight=1)
self.tabView.tab("HTML").grid_columnconfigure(0, weight=1)
self.template_text = customtkinter.CTkTextbox(master=self.tabView.tab('Text'))
self.template_text.pack(expand=True, fill='both')
self.template_text_html = customtkinter.CTkTextbox(master=self.tabView.tab('HTML'))
self.template_text_html.pack(expand=True, fill='both')
This obviously doesn't work. I'm struggling to understand the importing part, as well as properly naming things I think.
I'm looking to be guided in the right direction to make this app run, which I can then apply properly to my real app.

Is there a more efficient way to update labels on tkinter?

Here is my code. It works how I want it to but I have always been told it is poor coding practice to use global variables and that they can cause problems, although I cannot figure out how to get the labels to change without using them. Any help is appreciated.
import tkinter as tk
from tkinter import filedialog, Text
import os
status = 'Start'
startStopBG = 'light green'
def main():
root = configure_screen()
root.mainloop()
def configure_screen():
root = tk.Tk()
root.title('APP')
root.config(bg='snow3')
root.minsize(700, 700)
browse_button = tk.Button(root, text='Browse', width='10', command=browse)
browse_button.place(x=605, y=10)
global text
text = tk.Text(root, height=1.3, width=73)
text.insert(tk.END, 'Enter Path to Storage HERE')
text.place(x=10, y=13)
global start_stop
start_stop = tk.Button(root, height=1, width=12, text=status, bg=startStopBG,
font=('Helvetica', '40'), command=start_scanning)
start_stop.pack(pady=50)
return root
def browse():
path = filedialog.askdirectory(initialdir='/', title='Select where you want to save your file')
text.delete('1.0', tk.END)
text.insert(tk.END, path)
def start_scanning():
global status
global startStopBG
global start_stop
if status == 'Start':
status = 'Stop'
startStopBG = 'red'
else:
status = 'Start'
startStopBG = 'light green'
start_stop.config(text=status, bg=startStopBG)
if __name__ == '__main__':
main()
First of all you can use a class to your main window and instead of global variables you use class variables. Second I would recommend you to use tkinter variables to store important data from widget since the path and the status. For example, if you use text=tk.StringVar() you can set or get the value from text with text.set('value') or text.get(). Tkinter variables are object and if you define an object in your main you can access it as a global variable inside functions without the need of using global. However, in your code, to use text as a StringVar you should change the Text widget for an Entry widget, which is more appropriated since path is a single entry value and not a text. The same way you can change your start_stop button to a Checkutton and it will make the color change unnecessary since you can define colors for background and selectcolor.
The code bellow includes all changes I suggest here:
import tkinter as tk
from tkinter import filedialog, Text
import os
class Main(tk.Tk):
def __init__(self):
super(Main, self).__init__()
self.title('APP')
self.config(bg='snow3')
self.minsize(700, 700)
self.status = tk.IntVar()
self.text = tk.StringVar(self, value='Enter Path to Storage HERE')
browse_button = tk.Button(self, text='Browse', width='10',
command=self.browse)
browse_button.place(x=605, y=10)
tk.Entry(self, width=73, textvariable=self.text).place(x=10, y=13)
self.start_stop = tk.Checkbutton(self, height=1, width=12, text="start",
font=('Helvetica', '40'), indicator=False,
bg='light green', selectcolor='red',
variable=self.status, command=self.start_scanning)
self.start_stop.pack(pady=50)
def browse(self):
path = filedialog.askdirectory(initialdir='/', title='Select where you want to save your file')
self.text.set(path)
def start_scanning(self):
if self.status.get():
self.start_stop.config(text='stop')
else:
self.start_stop.config(text='start')
if __name__ == '__main__':
Main().mainloop()
As I understood you want to change label
Try This:
import tkinter as tk
def main():
def change_label_text():
mylabel.config(text="yeee My Text has Been changed")
def change_button_text():
mybutton.config(text="yee Button text has been changed")
root = tk.Tk()
root.title('Change Label')
root.config(bg='snow3')
root.geometry('400x300')
mybutton = tk.Button(root, text='Press Me To Change Button Text', command=change_button_text)
mybutton.pack(side='top')
mylabel = tk.Label(root, text='Press The Button Above To Change My text')
mylabel.pack(side='bottom')
mybutton2 = tk.Button(root, text="Press me", command=change_label_text)
mybutton2.pack(side='bottom')
root.mainloop()
main()
By making functions inside the mainloop you dont need to do global stuff and all

I need to update some Label Text from outside of the function that created it

I have a tkinter.Label created inside a function and from a totally seperate part of my code I need to update the text.
I have tried just about every solution google provides over the last hour and I can't get any of them to work, some error, some show blanks, some just fail to do anything.
I am creating the labels as follows
def createWindow():
window = tkinter.Tk()
container = tkinter.Frame(window, padx=5, pady=5)
summaryFrame = tkinter.Frame(container, bd=2, relief='groove')
summaryFrame.pack(side='top', fill='x')
summaryUser = tkinter.Label(summaryFrame, text='Some text').grid(row=1, column=1, sticky='w')
Much later I need to change the text of this label but because I'm no longer in this createWindow() function I don't have access to the summaryUser variable that contains the text.
I have tried summaryEvent["text"] (errors because it's not available), I have tried using a global variable and using textvariable=AGlobalVariable instead of text='Some text' (leaves the label text blank) and many other google results all with no success.
This seems like the sort of functionality that should be easier than this...
EDIT 1
I have tried the following...
summaryUserText = 'Some text'
def createWindow():
global summaryUserText
window = tkinter.Tk()
container = tkinter.Frame(window, padx=5, pady=5)
summaryFrame = tkinter.Frame(container, bd=2, relief='groove')
summaryFrame.pack(side='top', fill='x')
summaryUser = tkinter.Label(summaryFrame, textvariable=summaryUserText)
summaryUser.grid(row=1, column=1, sticky='w')
When I try this the label just starts blank, not with the content of the variable.
EDIT 2
I have also tried the following...
summaryUserText= tkinter.StringVar()
summaryUserText.set('Some text')
def createWindow():
...
summaryUser= tkinter.Label(summaryFrame, textvariable=summaryUserText)
But as soon as python sees the first line it errors with the following...
File "C:\Program Files\Python37\lib\tkinter\__init__.py", line 480, in __init__
Variable.__init__(self, master, value, name)
File "C:\Program Files\Python37\lib\tkinter\__init__.py", line 317, in __init__
self._root = master._root()
AttributeError: 'NoneType' object has no attribute '_root'
Edit 3
The simplest code that simulates the issue in one complete file
import tkinter
def loadEvent():
global summaryEventText
summaryEventText.set('Updated')
print('Updated')
def createWindow():
global summaryEventText
window = tkinter.Tk()
summaryEventText = tkinter.StringVar()
summaryEventText.set('Init')
summaryEventLabel = tkinter.Label(window, text='Event:').grid(row=0, column=0, sticky='e')
summaryEvent = tkinter.Label(window, textvariable=summaryEventText).grid(row=0, column=1, sticky='w')
window.mainloop()
createWindow()
loadEvent()
No errors, the print('Updated') works but the summaryEventText.set('Updated') does nothing.
The short answer is: to change an object you must have a reference to that object. That's not unique to tkinter, it's a fundamental aspect of programming. You're using local variables which by definition means you can't access the widgets outside of that function. The solution, then, is to not use local variables.
A proper solution requires you to save a reference that the other function can access, or provide a function that can return a reference. Have the function return a reference, use a global variable, or use a class variable.
The simplest solution for your specific example is to use a global variable. For example:
import tkinter
def loadEvent():
...
summaryEventLabel.configure(text='Updated')
...
def createWindow():
global summaryEventLabel
...
summaryEventLabel = tkinter.Label(window, text='Event:')
summaryEventLabel.grid(row=0, column=0, sticky='e')
...
createWindow()
loadEvent()
However, your specific example won't work because window.mainloop() will not return until the window is destroyed or you call its quit method. This means that createWindow won't return, so loadEvent will not be called.
If you were to structure your program to avoid this problem -- for example, calling loadEvent in response to a button click or some other event -- this solution would work.
Here's a working example that updates the label after 5 seconds:
import tkinter
def loadEvent():
summaryEventLabel.configure(text='Updated')
print('Updated')
def createWindow():
global summaryEventLabel
window = tkinter.Tk()
summaryEventText = tkinter.StringVar()
summaryEventText.set('Init')
summaryEventLabel = tkinter.Label(window, text='Event:')
summaryEventLabel.grid(row=0, column=0, sticky='e')
summaryEvent = tkinter.Label(window, textvariable=summaryEventText).grid(row=0, column=1, sticky='w')
window.after(5000, loadEvent)
window.mainloop()
createWindow()

How to effectively line up tkinter widgets

I have been a programmer for 40 years, but mostly command-line and system programming. I am converting a tcl/tk gui that I wrote to Python because much of the stuff I did in shell scripts can be done effectively in Python, but I'm having a bit of trouble making the wigets line up (using grid) the way I want them. In my example, note the buttons line up perfectly. But the label/entry widget pairs are not lining up the way I want them: Note the workspace/project in row 3. I want the label to be adjacent to the entry widget and center. Also at the bottom I would like to have the scroll text widen to it fills the width of the screen. I just need a couple of pointer, maybe how best to group things in multiple frames. Also, I am assuming that the grid rows and columns are relational to the root windows and not the frame.
"""
PYGUITEST - This is a GUI test to test alignments of fields
Author: Jerry Feldman
"""
import sys
import os
import Tix
import tkMessageBox
import ScrolledText
import getpass
from Tkconstants import *
class pyguitest:
def __init__(self):
self.mainWindow = Tix.Tk()
self.mainWindow.tk.eval('package require Tix')
def __createUI(self, mainWindow):
mainWindow.protocol("WM_DELETE_WINDOW", self.OnExitWindow)
###### major class variables
self.username = getpass.getuser()
self.topFrame = Tix.Frame(self.mainWindow)
self.topRight = Tix.Frame(self.mainWindow)
### define buttons
self.butn01 = Tix.Button(self.topFrame,text=u"Butn01",
command=self.OnButn01ButtonClick)
self.butn02 = Tix.Button(self.topFrame,text=u"Butn02",
command=self.OnButn02ButtonClick)
self.butn03 = Tix.Button(self.topFrame,text=u"Butn03",
command=self.OnButn03ButtonClick)
self.butn04 = Tix.Button(self.topFrame,text=u"Butn04",
command=self.OnButn04ButtonClick)
self.butn05 = Tix.Button(self.topFrame,text=u"Butn05",
command=self.OnButn05ButtonClick)
self.butn06 = Tix.Button(self.topFrame,text=u"Butn06",
command=self.OnButn06ButtonClick)
self.butn07 = Tix.Button(self.topFrame,text=u"Butn07",
command=self.OnButn07ButtonClick)
self.butn08 = Tix.Button(self.topFrame,text=u"Butn08",
command=self.OnButn08ButtonClick)
self.Butn09 = Tix.Button(self.topFrame,text=u"Butn09",
command=self.OnButn09ButtonClick)
self.kwit = Tix.Button(self.topRight,text=u"quit !",
command=lambda:self.mainWindow.destroy())
### Set up the buttons grids for row 0
self.butn01.grid(column=0,row=0, sticky="nw")
self.butn02.grid(column=1,row=0, sticky="nw")
self.butn03.grid(column=2,row=0, sticky="nw")
self.butn04.grid(column=3,row=0, sticky="nw")
self.butn05.grid(column=4,row=0, sticky="nw")
self.butn06.grid(column=5,row=0, sticky="nw")
self.butn07.grid(column=6,row=0, sticky="nw")
self.butn08.grid(column=7,row=0, sticky="nw")
self.Butn09.grid(column=8,row=0, sticky="nw")
self.topFrame.grid(column=0,row=1,columnspan=8,sticky="NW")
self.kwit.grid(column=0,row=0,sticky="NE")
self.topRight.grid(column=10,row=1,columnspan=1,sticky="NE")
Tix.Label(mainWindow,text="This label should be centered").grid(row=2,sticky="nwes",columnspan=8)
wsFrame=Tix.Frame(mainWindow).grid(row=3, columnspan=9)
Tix.Label(wsFrame,text="Workspace:").grid(row=3,column=0, sticky="e")
wsEntry=Tix.Entry(wsFrame)
ws="/home/myuser/workspaces/pyguitest"
wsEntry.config(width=len(ws))
wsEntry.insert(0, ws)
wsEntry.grid(row=3, column=1)
Tix.Label(wsFrame,text="Project: ").grid(row=3,column=2, sticky="e")
self.prEntry=Tix.Entry(wsFrame)
pr=ws+"/project"
self.prEntry.grid(row=3,column=3, sticky="w")
self.prEntry.insert(0, pr)
self.prEntry.config(width=len(pr)+1)
Tix.Label(mainWindow,text="This should also be centered" ).grid(row=4,columnspan=8)
Tix.Label(mainWindow, text="ProductHome: ").grid(row=5)
ProductHome="/pmount/groupname/ProductHome/homeversion"
self.ProductHomeEntry = Tix.Entry(self.mainWindow)
self.ProductHomeEntry.delete(0, END)
self.ProductHomeEntry.insert(0, ProductHome)
self.ProductHomeEntry.configure(width=len(ProductHome)+1)
self.ProductHomeEntry.grid(row=5, column=1)
Tix.Label(mainWindow, text="Starting Port: ").grid(row=5,column=3, sticky="e")
portEntry=Tix.Entry(mainWindow)
portEntry.grid(row=5,column=4, sticky="w")
startingPort="20000"
portEntry.insert(0,startingPort)
portEntry.config(width=len(startingPort)+1)
Tix.Label(mainWindow, text="Product Version: ").grid(row=5,column=5, sticky="e")
pVersion="10.12.8 beta"
self.productVersionEntry=Tix.Entry(mainWindow)
self.productVersionEntry.grid(row=5, column=6, sticky="w")
self.productVersionEntry.insert(0, pVersion)
self.productVersionEntry.config(width=len(pVersion))
Tix.Label(mainWindow,text="Another centered label").grid(row=6, columnspan=8)
Tix.Label(mainWindow, text="Delta:").grid(row=7, column=0)
delta=ProductHome+"/delta"
self.deltaEntry=Tix.Entry(mainWindow)
self.deltaEntry.insert(0, delta)
self.deltaEntry.grid(row=7, column=1, sticky="w")
self.deltaEntry.configure(width=len(delta))
Tix.Label(mainWindow, text="Job to run: ").grid(row=7, column=2, sticky="e")
defaultJob=ProductHome+"/jobs/default.sh"
self.jobToRunEntry=Tix.Entry(mainWindow)
self.jobToRunEntry.grid(row=7, column=3, sticky="w")
self.jobToRunEntry.delete(0,END)
self.jobToRunEntry.insert(0, defaultJob)
self.jobToRunEntry.config(width=len(defaultJob))
defaultLauncher=ProductHome+"/launcher/default.sh"
Tix.Label(mainWindow, text="Launcher: ").grid(row=7, column=4, sticky="e")
self.launcherEntry=Tix.Entry(mainWindow)
self.launcherEntry.grid(row=7, column=5, sticky="w")
self.launcherEntry.delete(0,END)
self.launcherEntry.insert(0, defaultLauncher)
self.launcherEntry.config(width=len(defaultLauncher))
self.logger = ScrolledText.ScrolledText(self.mainWindow,
width = 160,
height = 60,
wrap=Tix.WORD,
relief="sunken")
self.logger.grid(row=10,columnspan=8)
def doLog(self, file):
for line in file.read().splitlines():
self.logger.insert(END, line+"\n")
txt.insert(END, "\nEnd of command\n\n")
def startpyguitest(self):
self.__createUI(self.mainWindow)
self.mainWindow.mainloop()
## Button Actions
def OnExitWindow(self):
self.mainWindow.destroy()
def OnButn01ButtonClick(self):
pass
def OnButn02ButtonClick(self):
pass
def OnButn03ButtonClick(self):
pass
def OnButn04ButtonClick(self):
pass
def OnButn05ButtonClick(self):
pass
def OnButn06ButtonClick(self):
pass
def OnButn07ButtonClick(self):
pass
def OnButn08ButtonClick(self):
pass
def OnButn09ButtonClick(self):
pass
def logIt(self, stdout):
for line in stdout.read().splitlines():
self.logger.insert(END, line+"\n")
self.logger.see(END)
if __name__ == "__main__":
pyguitest = pyguitest()
pyguitest.startpyguitest()
You need to make more use of the sticky option. There are a few widgets -- such as the scrolled text widget -- where they aren't told to stick to the edges of their cell.
You'll also want to use the grid_rowconfigure and grid_columnconfigure methods to get your GUI to resize properly.
You are incorrect about the grid rows and columns. They are relative to the frame. For example, you can have things in column 0 of an inner frame, and have that inner frame at column 2 of the root window.
I would use a .grid
btn.grid(row=0, column=0)
(change the #s as needed)

displaying file name, not content in text widget tkinter Python

I've no idea why I haven't been able to find a good solution to this problem yet, it seems very elementary to me .. though not elementary enough to figure it out satisfactorily.
A chapter project in a cryptology book Im reading instructs to write a simple mono-alphabetic cipher in your preferred language ... I chose Python.
It starts with a simple tkinter app. with some widgets, lol ... duh. Anyways here's the relevant code:
from tkinter import *
from tkinter.filedialog import askopenfilename
from tkinter.messagebox import showerror
class Application(Frame):
def __init__(self, master):
""" Initialize Frame. """
super(Application, self).__init__(master)
self.grid()
self.create_widgets()
def create_widgets(self):
""" Set all program widgets. """
# set all labels
Label(self, text = "Plaintext File: ")\
.grid(row=0, column=0, sticky=W)
Label(self, text = "Ciphertext: ")\
.grid(row=3, column=0, sticky=W)
Label(self, text = "Offset: ")\
.grid(row=2, column=0, sticky=W)
# set buttons
Button(self, text = "Browse", command=self.load_file, width=10)\
.grid(row=1, column=0, sticky=W)
# set entry field
self.file_name = Text(self, width=39, height=1, wrap=WORD)
self.file_name.grid(row=1, column=1, columnspan=4, sticky=W)
# set display field
self.output_display = Text(self, width=50, height=5, wrap=WORD)
self.output_display.grid(row=4, column=0, columnspan=4, sticky=W)
# set offset amount spinbox
self.offset_amt = IntVar()
self.offset_amt = Spinbox(self, from_=1, to=13)
self.offset_amt.grid(row=2, column=1, sticky=W)
# set shift direction
self.shift_dir = StringVar()
self.shift_dir.set('r')
Radiobutton(self, text="Shift Right", variable=self.shift_dir, value='r')\
.grid(row=2, column=2, sticky=W)
Radiobutton(self, text="Shift Left", variable=self.shift_dir, value='l')\
.grid(row=2, column=3, sticky=W)
def load_file(self):
self.filename = askopenfilename(initialdir='~')
if self.filename:
try:
#self.settings.set(self.filename)
self.file_name.delete(0.0, END)
self.file_name.insert(0.0, open(self.filename, 'r'))
except IOError:
showerror("Open Source File", "Failed to read file \n'%s'"%self.filename)
return
def main():
root = Tk()
root.title("simple mono-alpha encrypter")
root.geometry('450x250')
app = Application(root)
for child in app.winfo_children():
child.grid_configure(padx=3, pady=3)
root.mainloop()
main()
There's only a very little of it that actually does anything besides create widgets right now, I decided to post it all since its not that involved yet and someone can get a good idea of where Im at.
My problem that I haven't solved is that when I press use the 'Browse' button to choose a file to encrypt and then choose the file, the file content is displayed in the 'file_name' text widget, rather than the file name itself.
Im thinking that I have to change the 'filename' variable to not the actual file name but the file instead and then load the content of the File Name field from the open file dialog box in a 'filename' variable. I just haven't been able to figure out how to do that yet.
Nor have I come across an appropriate method to do it.
Any guidance??
Thanks
F
Displaying the Filename
self.file_name.insert(0.0, self.filename)
Displaying the File Contents
You just need to read the data in from the file. See http://docs.python.org/library/stdtypes.html#file-objects
with open(self.filename, 'r') as inp_file:
self.file_name.insert(0.0, inp_file.read())

Categories

Resources