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

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

Related

how to solve this: how to clear the tkinter label with button

I'm using tkinter.
I have a button to create a label with text in it. I want to clear that label with another button.
How can i do that?
I'm pretty new on tkinter. ıs there somebody to lead me
Here are a few options
Option 1
import tkinter as tk
root = tk.Tk()
label = tk.Label(root, text='Clear Me!')
label.pack()
# define a function to set the label text to an empty string
def clear_label_text():
label.config(text='')
# set up a button to call the above function
btn_clear = tk.Button(
root,
text='Click to Clear Label',
command=clear_label_text # note the lack of '()' here!
)
btn_clear.pack()
if __name__ == '__main__':
root.mainloop() # start the app
Option 2
This is a similar approach, but instead of defining a function to clear the label, we'll use a lambda (an anonymous function)
import tkinter as tk
root = tk.Tk()
label = tk.Label(root, text='Clear Me!')
label.pack()
# set up a button to clear the label
btn_clear = tk.Button(
root,
text='Click to Clear Label',
# lambdas make for clean code, but don't go crazy!
command=lambda: label.config(text='')
)
btn_clear.pack()
if __name__ == '__main__':
root.mainloop() # start the app
Neither of these methods will outright destroy the label, so you can set it's text again at any time a la label.config(text='New and improved text!')
from tkinter import *
root = Tk()
lab1 = Label(root, text = "Hello World")
lab1.pack()
but1 = Button(root, text = "clear", command=lab1.destroy)
but1.pack()
root.mainloop()

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.

How to run a function as a button command in tkinter from a 2nd window

Hi I am pretty new to tkinter and have being trying to create a button that opens a window then a have a button in the new window the gives a message when pressed. I ran into the problem that the only whay I could get it to recognise the function I wrote was to write it inside the function that opens the second window. I don't know if I have being searching for the wrong things but I can't find how to do this properly. Can someone help me out Here is my code
from tkinter import *
master = Tk()
master.title("frame control")
def win():
window2 = Toplevel()
def open():
stamp = Label(window2, text="Staped").pack()
lab2 = Button(window2,text = "yo ",command = open).pack()
lab1 = Button(master,text = " open a new window" , command = win).pack()
mainloop()
This is your code but with best practises:
import tkinter as tk
def create_stamp():
stamp = tk.Label(window2, text="Stamp")
stamp.pack()
def create_second_win():
global window2
window2 = tk.Toplevel(root)
lab2 = tk.Button(window2, text="Click me", command=create_stamp)
lab2.pack()
root = tk.Tk()
root.title("Frame control")
button = tk.Button(root, text="Open a new window", command=create_second_win)
button.pack()
root.mainloop()
I made window2 a global variable so that I can access it from create_stamp. Generally it is discouraged to use from ... import *. As #Matiiss said, sometimes you can have problems with global variables if you don't keep track of the variable names that you used.
If you want to avoid using global variables and want to use classes, look at this:
import tkinter as tk
class App:
def __init__(self):
self.stamps = []
self.root = tk.Tk()
self.root.title("Frame control")
self.button = tk.Button(self.root, text="Open a new window", command=self.create_second_win)
self.button.pack()
def create_stamp(self):
stamp = tk.Label(self.window2, text="Stamp")
stamp.pack()
self.stamps.append(stamp)
def create_second_win(self):
self.window2 = tk.Toplevel(self.root)
self.lab2 = tk.Button(self.window2, text="Click me", command=self.create_stamp)
self.lab2.pack()
def mainloop(self):
self.root.mainloop()
if __name__ == "__main__":
app = App()
app.mainloop()
As #Matiiss mentioned it would be more organised if you move the second window to its own class. For bigger projects it is a must but in this case you don't have to.

Tkinter class function causing an error when trying to utilize the entry widget

Please help me with this error. I am very confused as to why I cannot reference and obtain the contents of the entry. If someone can please help, it will be very greatly appreciated. If you need anymore context on what the problem is, please leave a comment.
When I run the program I get an error which says
self.file_location = file_location_entry.get()
NameError: name 'file_location_entry' is not defined
I am confused for getting this error since I have defined this variable below inside of the class in the main initializer function.
# Imports
import tkinter as tk
from tkinter import ttk
# ==================================================================================================
class GUI():
# Global variable for file location of software to scan
global file_location
# ==================================================================================================
# Button Functions for Windows
# Function used to open other window that will be used for the script based attacks
def script_attack_window(self):
pass
# Close Window Button Command
def close_window(self, window):
return window.quit
# Start Audit Button Command
def start_audit(self):
#function to start the security audit
pass
# Display Text To Textbox Command
def display_text_to_textbox(self, text):
self.display_textbox.insert(tk.END, text)
def set_variable(self):
self.file_location = self.file_location_entry.get()
self.display_text_to_textbox(self.file_location)
# Window for entering default location for auditing tool
def default_location_auditing_tool_window(self):
pass
# ==================================================================================================
# Main Window Function
# Rescource for using frames to organize the window better
# https://stackoverflow.com/questions/2261191/how-can-i-put-2-buttons-next-to-each-other
# https://www.tutorialspoint.com/python/tk_frame.htm
# https://realpython.com/python-gui-tkinter/
# https://tkdocs.com/tutorial/
# This will be used to display the main menu when called
def __init__(self):
# Initializing a new window
root = tk.Tk()
root.title("Main Menu")
# Making frames
canvas = tk.Frame()
blocked_space = tk.Frame(canvas)
# Initializing the window settings
root.attributes('-type', 'dialog')
#=======================Buttons=========================
# Button to start the autiting software
auditing_button = tk.Button(master=canvas, text="Audit", command=self.start_audit())
# Button to close the window
close_button = tk.Button(master=canvas, text="Close", command=self.close_window(root))
# Button to open script page
script_button = tk.Button(master=canvas, text="Script Attack", command=self.script_attack_window())
# Button to set the file variable
file_enter_button = tk.Button(master=canvas, text="Enter File Path", command=self.set_variable())
# Textbox for getting user input for file location
self.file_location_entry= tk.Entry(master=canvas)
# TextBox for displaying the text
self.display_textbox = tk.Text(master=canvas)
# Plotting the buttons and textboxes and entry on the grid
canvas.grid(column=0, row=0)
auditing_button.grid(row=3, column=1)
auditing_button.columnconfigure(1, weight=1)
close_button.grid(row=3, column=0)
close_button.columnconfigure(0, weight=1)
script_button.grid(row=3, column=2)
script_button.columnconfigure(2, weight=1)
file_enter_button.grid(column=0, row=0)
self.file_location_entry.grid(column=0, row=1, columnspan=3, sticky="ewn")
self.display_textbox.grid(column=3, row=1)
# Starting the window mainloop
root.mainloop()
# ==================================================================================================
# ---------------------------------------------------------------------------------------------------
x = GUI()
~ ```
I think that the problem is in the order in which you write the code.
Below I've rewritten your script in full OO mode, that's mean without the use
of the global variable and the double passage to assign to the text the value
of the entry variable and with the right sequence, first the app callbacks and
app variables, after GUI init, and finally the callbacks.
#!/usr/bin/python3
import sys
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
class App(tk.Tk):
"""Main Application start here"""
def __init__(self):
super().__init__()
self.protocol("WM_DELETE_WINDOW", self.on_close)
self.title("Simple App")
#never use global...
self.text = tk.StringVar()
self.init_ui()
def init_ui(self):
w = ttk.Frame(self, padding=5)
r = 0
c = 0
self.file_location_entry = ttk.Entry(w,
justify=tk.LEFT,
textvariable=self.text)
self.file_location_entry.grid(row=r, column=c, sticky=tk.W+tk.E, padx=5, pady=5)
r += 1
self.display_textbox = tk.Text(w)
self.display_textbox.grid(row=r, column=c, padx=5, pady=5)
r = 0
c = 1
b = ttk.LabelFrame(self, text="", relief=tk.GROOVE, padding=5)
bts = [("Audit", 1, self.start_audit, "<Alt-a>"),
("Enter File Path", 0, self.set_variable, "<Alt-e>"),
("Script Attack", 0, self.script_attack_window, "<Alt-s>"),
("Close", 0, self.on_close, "<Alt-c>")]
for btn in bts:
ttk.Button(b, text=btn[0], underline=btn[1], command = btn[2]).grid(row=r,
column=c,
sticky=tk.N+tk.W+tk.E,
padx=5, pady=5)
self.bind(btn[3], btn[2])
r += 1
b.grid(row=0, column=1, sticky=tk.N+tk.S)
w.grid(row=0, column=0, sticky=tk.N+tk.W+tk.S+tk.E)
def start_audit(self, evt=None):
pass
def script_attack_window(self, evt=None):
pass
def set_variable(self, evt=None):
self.display_textbox.insert(tk.END, self.text.get())
def on_close(self,evt=None):
"""Close all"""
if messagebox.askokcancel(self.title(), "Do you want to quit?", parent=self):
self.destroy()
def main():
app = App()
app.mainloop()
if __name__ == '__main__':
main()

Tkinter GUI does not respond

I'm new to programming and I'm trying to run a program that asks a user for a directory which which they will move their files to.
import tkinter as tk
from tkinter import filedialog, ttk
class Unzip():
def __init__(self):
# initialising the screen name, size title
root = tk.Tk()
root.geometry('650x550')
root.title("Move Files")
root.resizable(0, 0)
root.configure(bg='#002060')
# Initialising the frame to insert our widget
top_frame = tk.Frame(root, bg='#002060')
button_top = tk.Frame(root, bg='#002060')
button_bottom = tk.Frame(root, bg='#002060')
footer_frame = tk.Frame(root, bg='#002060')
top_frame.pack(side='top', fill='both')
button_top.pack(side='top', fill='both')
button_bottom.pack(side='top', fill='both')
footer_frame.pack(side='bottom', fill='both')
# Setting the title name
label_title = tk.Label(top_frame, text='Move Files', font='Arial 36 bold', fg='#948a54',
bg='#002060', pady=60)
label_title.pack(side='top')
# call button to get output file
output_file = ttk.Button(button_bottom, text='Choose location to save files', width=25, command=self.output_path)
output_file.pack(side='left', padx=(120, 10), pady=10)
root.mainloop()
# Get output directory
def output_path(self):
self.output_file_dir = filedialog.askdirectory()
if __name__ == '__main__':
Unzip()
The problem is that when you run the program and try to run the output_file button, the program will not be responding. I decided to use the self because I wanted it to be accessible to other instance methods that I want to create that will use the directory output_path.
So what exactly are you expecting? Your program does respond, but it is not supposed to do anything with the information.
Try
def output_path(self):
self.output_file_dir = filedialog.askdirectory()
print(self.output_file_dir)
Do you see what happens?
Maybe example 2 from this link can help you: https://www.programcreek.com/python/example/95888/tkinter.filedialog.askdirectory

Categories

Resources