Why doesnt my label refresh with newly entered data in tkinter? - python

My goal was to refresh a label with its new contents on the click of a button, but when i click the button i get the error message below the code. I understand that it cant access the variable, but i dont understand why. How do i fix it and make the label update when i enter new text in the entry box and click the change button?
Main.py:
import tkinter as tk
from tkinter import *
from tkinter import ttk
from tkinter.messagebox import showinfo # Message Box
from functions import *
root = tk.Tk()
current_title = Label(root, text=homepage.get_title())
current_title.grid(row=1, column=0, sticky=E)
def refresh_title_label():
current_title.destroy()
current_title = Label(root, text=homepage.get_title()) # this homepage.get_title() gets the text from a html file
current_title.grid(row=1, column=1, sticky=W)
def change_title():
x = new_title_input.get()
homepage.change_title(x) # this changes the title in the html file
refresh_title_label()
showinfo('Title Changed')
new_title_label = Label(root, font='Helvetica 15', text='New Title: ' )
new_title_input = Entry(root, background='lightgrey', width=50 )
title_button = ttk.Button(root, text='Change', command=change_title)
new_title_label.grid(row=2, column=0, sticky=E)
new_title_input.grid(row=2, column=1, sticky=W)
title_button.grid(row=2, column=2, sticky=W)
if __name__ == "__main__":
root.mainloop()
functions.py:
# Importing the ssh connection
from ssh_config import *
# This is a class to change the index file
class homepage():
# Gets the website title
def get_title():
data = ssh_command('grep web_title index.html')
data = data[26:]
data = data[:-11]
return data
# changes website title
def change_title(new_title):
current_title = homepage.get_title()
ssh_command(f"sed -i 's/{current_title}/{new_title}/g' index.html")
This is the error message:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\josep\AppData\Local\Programs\Python\Python311\Lib\tkinter\__init__.py", line 1948, in __call__
return self.func(*args)
^^^^^^^^^^^^^^^^
File "c:\Users\josep\Desktop\tkinter-ssh-backend\Untitled-1.py", line 20, in change_title
refresh_title_label()
File "c:\Users\josep\Desktop\tkinter-ssh-backend\Untitled-1.py", line 12, in refresh_title_label
current_title.destroy()
^^^^^^^^^^^^^
UnboundLocalError: cannot access local variable 'current_title' where it is not associated with a value
I tried making the variable global but that didnt work
root = tk.Tk()
global current_title
current_title = Label(root, text=homepage.get_title())
current_title.grid(row=1, column=0, sticky=E)
And i have tested to see if the ssh is working correctly and it is.

In main.py, you cannot put current_title.destroy() before current_title = Label(root). You do this after current_title.grip()
If you want to destroy Label(), you can't do simultaneous in the
refresh_title_label() function.
You can put current_title.destroy() in the change_title() function.
It is up to you to suit your need.
Add current_title.config in the refresh_title_label() function.
I am not using ssh_config. I can do workaround to show.
Snippet:
def refresh_title_label():
current_title.config(text=new_title_input.get())
current_title.grid(row=1, column=0, sticky=E)
def change_title():
x = new_title_input.get()
homepage.change_title(x) # this changes the title in the html file
refresh_title_label()
showinfo('Title Changed')
current_title.destroy()
current_title = Label(root, text=homepage.get_title())
Screenshot:
Screenshot after clicking Change button:
Screenshot destroy the Label:

Related

Returning File Path From tk GUI

I using tkinter and tkinterdnd2 to make a drag and drop GUI (I am using the below code). How do I return the value of the path name to use later? When I try to print(get_path) it returns this <function get_path at 0x10cfa10d0> or if I set a global varible = event I get <tkinterdnd2.TkinterDnD.DnDEvent object at 0x164cef0d0>
def get_path(event):
pathLabel.configure(text=event.data)
root = TkinterDnD.Tk()
root.geometry("350x100")
root.title("Get file path")
nameVar = StringVar()
entryWidget = Entry(root)
entryWidget.pack(side=TOP, padx=5, pady=5)
pathLabel = Label(root, text="Drag and drop file in the entry box")
pathLabel.pack(side=TOP)
entryWidget.drop_target_register(DND_ALL)
entryWidget.dnd_bind("<<Drop>>", get_path)
Button(root, text="Close", command=root.destroy).pack()
root.mainloop()

Python3 Tkinter name error (not defined) on user input

I'm getting the following error:
Exception in Tkinter callback
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/tkinter/__init__.py", line 1705, in __call__
return self.func(*args)
File "/Users/XXXXXXXXXXXXX/Desktop/Python/Test Py/TestGUI.py", line 37, in trans1
print(enter_principal)
NameError: name 'enter_principal' is not defined
I'm currently trying to learn python, so I'd be lying if I said I had any idea on what is going wrong. Here is my source code, trying to make a basic compound interest calculator. Getting this error when I'm trying to get an input from the user. Code:
#Importing GUI Module
import tkinter as tk
from tkinter import *
#Creating window
root = tk.Tk()
####Functions#####
#Root screen exit button
def exitroot():
root.destroy()
#principal input
def principal():
#Creating principal window and destroying home window
window = tk.Tk()
exitroot()
#Creating widgets
title_principal = tk.Label(window, text='Please enter your pricipal value: ')
enter_principal = tk.Entry(window)
b1 = tk.Button(window, text='Submit', command=trans1)
title_principal.grid()
enter_principal.grid()
b1.grid()
def trans1():
#temp function for testing purposes
print(enter_principal)
####
#CREATING HOME WINDOW WIDGETS
title_main = tk.Label(root, text="Compound Intrest Calculator", font=("Arial", 20, 'bold'))
start_button = tk.Button(root, text="Start", width='6', height='2', command=principal)
exit_button = tk.Button(root, text="Exit", width='6', height='2', command=exitroot)
credits_main = tk.Label(root, text="M.CXXXXXXXX 2020", font=("Arial", 8))
#PACKING HOME WINDOW WIDGETS VIA GRID
title_main.grid(row='0', columnspan='2')
start_button.grid(row='1', column='0')
exit_button.grid(row='1', column='1')
credits_main.grid(row='2', columnspan='2')
root.mainloop()
Any help is greatly appreciated! I apologise if my code is hard to follow or has blantant errors. I've spent some time looking for a fix but I am really struggling as none have worked.
You need to change
b1 = tk.Button(window, text='Submit', command=trans1)
TO:
b1 = tk.Button(window, text='Submit', command=lambda: trans1(enter_principal.get()))
The reason being is because you need to pass in the value typed into the tk.Entry by using enter_principal.get().
Lambda allows the function to be called only when the button is pressed.(since the command contains parenthesis and so would be called automatically)
Once you've passed this in, you can then pass it into the trans1 function and print it.
def trans1(answer):
# temp function for testing purposes
print(answer)

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

Take in a input using tkinter clicking a button and then returning whatever I typed in to be able to pass it into other functions

I'm very new to the tkinter module and have little to no experience with it.
I want to make a program where I could run it and an entry box would display as well as a button.
What I want the program to do is, when I left click the button, the canvas would close, and I would be able to assign a variable to the entry I typed in and be able to pass that to other functions. So I'd have tkinter.Entry('Type in text'), then after that I would click the tkinter.Button('Click Me'), and once I click the button the canvas would close and then be able to assign the tkinter.Entry as a variable that I could pass through to other functions.
In my program I was able to just do regular python without the canvas and type in an input() and then return that to my other functions, but I'm completely lost on how to remove the input() from console and replace it with a UI canvas with tkinter. Sorry if this isn't making a lot of sense.
import tkinter
window = tkinter.Tk()
window.title("Code Violation")
def Canvas():
keyword = tkinter.Label(window, text="Enter Keyword").grid(row=0)
tester = tkinter.Button(window, text="Generate File").grid(columnspan=2)
tkinter.Entry(window).grid(row=0, column=1)
window.mainloop()
----Afterwards Error Codes
Traceback (most recent call last):
File "C:/Users/oalbz/PycharmProjects/Code_Violation/CodeViolation.py", line 98, in <module>
main()
File "C:/Users/oalbz/PycharmProjects/Code_Violation/CodeViolation.py", line 29, in main
keyword = Canvas()
File "C:/Users/oalbz/PycharmProjects/Code_Violation/CodeViolation.py", line 12, in Canvas
Var = tkinter.StringVar()
File "C:\Users\oalbz\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 480, in __init__
Variable.__init__(self, master, value, name)
File "C:\Users\oalbz\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 317, in __init__
self._root = master._root()
AttributeError: 'NoneType' object has no attribute '_root'
I want to be able to take the entry.get() that's insie the callback function and return it to my main and use that as a parameter in my vacancy function
here is the code for my main
def main():
#Canvas()
keyword = Canvas()
print(keyword)
initial_index = open('CodeViolationIndex.html','r')
table_dict = removeTags(initial_index,'tr','td')
site_final_html = open('test.html','w')
#keyword = input('Enter Keyword you would like to search:')
vacancy(table_dict,keyword)
This is what I have so far in my Canvas function you gave me
def Canvas():
Var = tkinter.StringVar()
tkinter.Label(window, text="Enter Keyword").grid(row=0)
entry = tkinter.Entry(window, text="Enter Keyword",textvariable = Var)
entry.grid(row=1)
def callback():
keyword = entry.get()
#print(keyword)
window.destroy()
return keyword
tester = tkinter.Button(window, text="Generate File",command=callback)
tester.grid(columnspan=2)
keyword = callback()
return keyword
Try this code:
import tkinter
window = tkinter.Tk()
window.title("Code Violation")
def Canvas():
Var = tkinter.StringVar() #Making a variable which will store data
tkinter.Label(window, text="Enter Keyword:").grid(row=0) #Making label, no need to store it in a variable
entry = tkinter.Entry(window, text="Enter Keyword", textvariable = Var) #making entry
entry.grid(row=1)
def callback(): #this function will be triggered on button press
print(entry.get()) #get() method will give the value of the entry
window.destroy() #It will destroy the tkinter window
tester = tkinter.Button(window, text="Generate File", command = callback)
tester.grid(columnspan=2)
Canvas()
window.mainloop()
Edit:
Here is the code updated according to your updates:
import tkinter
def Canvas():
global keyword
window = tkinter.Tk()
window.title("Code Violation")
Var = tkinter.StringVar()
tkinter.Label(window, text="Enter Keyword").grid(row=0)
entry = tkinter.Entry(window, text="Enter Keyword",textvariable = Var)
entry.grid(row=1)
def callback():
global keyword
keyword = entry.get()
window.destroy() #This also quits the mainloop so function will continue to return statement
tester = tkinter.Button(window, text="Generate File",command=callback)
# >>>> >>>> >>>> ^ We are assigning the function callback here
tester.grid(columnspan=2)
window.mainloop()
return keyword
def main():
#Canvas()
keyword = Canvas()
print(keyword)
#...
main()

Python Tk Label Error with StringVar

I'm going to create a program that resembles the image below. The interface uses one text entry for a name, one button, and two labels. The button should have the text Say hello and when the user clicks the button, the bottom label should display the name with Hi in front of it (see image below)
Here's what I've got
from tkinter import *
from tkinter.ttk import *
def say_hello():
name_var.set(name_entry.get())
def main():
global window, name_var, name_entry
window = Tk()
top_label = Label(window, text='Enter a name below')
top_label.grid(row=0, column=0)
name_var = StringVar()
name_entry = Entry(window, textvariable=name_var)
name_entry.grid(row=1, column=0)
hello_button = Button(window, text='Say hello', command=say_hello)
hello_button.grid(row=2, column=0)
bottom_label = Label(window, text='Hi ' + name_var)
bottom_label.grid(row=3, column=0)
window.mainloop()
main()
When I try to run it I get this error:
Traceback (most recent call last): File "C:\Program Files (x86)\Wing IDE 101 5.1\src\debug\tserver_sandbox.py", line 29, in <module> File "C:\Program Files (x86)\Wing IDE 101 5.1\src\debug\tserver_sandbox.py", line 24, in main builtins.TypeError: Can't convert 'StringVar' object to str implicitly
Everything works GUI wise, I'm just not sure how to get the last label that says "Hi Jack" to come up after pressing the button — i.e what my command should be in the hello_button line.
Here's your offensive code:
bottom_label = Label(window, text='Hi ' + name_var)
You can't really add a string and an instance of a class. A Tkinter StringVar isn't actually a string, but like a special thing for the gui to hold a string. That's why it can update automatically and stuff like that. Solution is simple:
bottom_label = Label(window, text = 'Hi ' + name_var.get())
Here's how I did it:
#!/usr/bin/env python2.7
import Tkinter as tk
class Application(tk.Frame):
def __init__(self, master=None):
self.name_var = tk.StringVar()
tk.Frame.__init__(self, master)
self.pack()
self.createWidgets()
def createWidgets(self):
self.top_label = tk.Label(self, text='Enter a name below')
self.top_label.grid(row=0, column=0)
self.name_entry = tk.Entry(self)
self.name_entry.grid(row=1, column=0)
self.hello_button = tk.Button(self, text='Say hello', command=self.say_hello)
self.hello_button.grid(row=2, column=0)
self.output = tk.Label(self, textvariable=self.name_var)
self.output.grid(row=3, column=0)
def say_hello(self):
self.name_var.set("Hi {}".format(self.name_entry.get()))
root = tk.Tk()
app = Application(master=root)
app.mainloop()
Ultimately it was very similar to your code. The only thing you were missing was how to use Tkinter.StringVar() correctly. You need to set the bottom label's textvariable to name_var when you create it, and then you should be good to go.
This simple class should do what you want:
from tkinter import Button, Tk, Entry,StringVar,Label
class App():
def __init__(self, **kw):
self.root = Tk()
# hold value for our output Label
self.s = StringVar()
# label above our Entry widget
self.l = Label(self.root, text="Enter name here").pack()
# will take user input
self.e = Entry(self.root)
self.e.pack()
self.b = Button(self.root, text="Say Hello",command=self.on_click).pack()
# textvariable points to our StringVar
self.l2 = Label(self.root, textvariable=self.s).pack()
self.root.mainloop()
# every time the Button is pressed we get here
# an update the StringVar with the text entered in the Entry box
def on_click(self):
self.s.set(self.e.get())
App()
You just need to create a couple of Labels, and Entry widget to take the name and a callback function to update the StringVar value so the label/name value gets updated.

Categories

Resources