Refresh tkinter label automatically not on button press - python

Hi there i am building a short game in tkinter and would like to be able to output to the user via a label within my tkinter window. I have looked at past questions and found no help apart from getting it to refresh using a button which is not what i want it to do. In short i need to have it refresh everytime a variable is changed.
My code :
import tkinter as tk
import time
root = tk.Tk()
root.resizable(width=False, height=False)
w = 800 # width for the Tk root
h = 500 # height for the Tk root
ws = root.winfo_screenwidth() # width of the screen
hs = root.winfo_screenheight() # height of the screen
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
root.geometry('%dx%d+%d+%d' % (w, h, x, y))
wheat=10
money=0
title=tk.Label(root, text="The Farm Game")
title.config(font=('times', 20, 'bold'))
title.place(height=30, width=300, x = 250 , y = 10)
def advance():
moneyguidisplay = tk.StringVar()
moneyshowed = ("£", money)
moneyguidisplay.set(moneyshowed)
moneygui = tk.Label(root, wraplength=200, textvariable=moneyguidisplay)
moneygui.config(bg='lightgreen', font=('times', 15, 'bold'))
moneygui.place(height=30, width=200, x=600, y=60)
Usershow = tk.StringVar()
shownow = ("Welcome to The farm game")
Usershow.set(shownow)
USER = tk.Label(root, wraplength=200, textvariable=Usershow)
USER.config(bg='lightpink', font=('times', 15, 'bold'))
USER.place(height=200, width=400, x=200, y=100)
wheatguidisplay = tk.StringVar()
wheatshowed = ("Wheat:", wheat)
wheatguidisplay.set(wheatshowed)
Wheatgui = tk.Label(root, wraplength=200, textvariable=wheatguidisplay)
Wheatgui.config(bg='lightblue', font=('times', 15, 'bold'))
Wheatgui.place(height=30, width=200, x=0, y=60)
root.after(100, advance)
root.after(100, advance)
root.mainloop()

Your question is a little unclear, but what I can understand is that you want to be able to change the text of a Label, depending on the value of another variable(correct me if I'm wrong). You can use the config method to do so. I have written a small function for it, you can put it in your program.
from tkinter import*
root=Tk()
L=Label(text="Label text changing after 5 sec")
L.grid()
# Call this function where the value of your variable/number changes
def ChangeValue(num):
L.config(text=str(num))
print("Value Changed")
root.update()
root.after(5000,lambda :ChangeValue("Text Changed!"))
root.mainloop()

Related

tkinter text button change size

My GUI app takes this text in first TextBox:
< C:\Users\user\OneDrive\Desktop\200-301-CCNA.pdf >
SHA-256: 68C3A9BC97E6303DAD3DB60028290B31DD77424A7C9A4F967FB531A47D17E4A2
If I click on Prelucreaza Button, I will obtain in second TextBox this:
200-301-CCNA.pdf
SHA-256: 68C3A9BC97E6303DAD3DB60028290B31DD77424A7C9A4F967FB531A47D17E4A2
Now I'm trying to resize my TextBoxes, but if I change height or width in this line nothing happened (in GUI height will always be 40 and width 30).
text_multihasher = Text_Local(height=40, width=30, font=("Times New Roman", 12))
This is my code:
main.py
import tkinter
from tkinter import *
from text_local import Text_Local
window = Tk()
window.title("Sha 256")
window.minsize(width=680, height=900)
window.config(padx=20, pady=20)
window.resizable(False, False)
def click_button():
text_prelucrat.delete(1.0, END)
multihash = text_multihasher.readlines()
multihash_fara_pauza = []
for hash in multihash:
if hash != "":
multihash_fara_pauza.append(hash)
index_gasit = ""
for index in range(0, len(multihash_fara_pauza)):
if index % 2 == 0:
denumire_fisier = multihash_fara_pauza[index]
for i in range(0, len(denumire_fisier)):
if denumire_fisier[i] == '\\':
index_gasit = i
text_prelucrat.insert(END, f"{denumire_fisier[index_gasit+1:-2]}\n")
if index % 2 == 1:
text_prelucrat.insert(END, f"{multihash_fara_pauza[index][2:]}\n")
text_prelucrat.insert(END, f"\n")
label_1 = Label(text="Introdu mai jos ce obtii in Multihasher:")
label_1.grid(column=0, row=0)
text_multihasher = Text_Local(height=40, width=30, font=("Times New Roman", 12))
text_multihasher.grid(column=0, row=1)
button = Button(text="Prelucreaza", command=click_button)
button.grid(column=0, row=2)
text_prelucrat = Text_Local(height=40, width=30, font=("Times New Roman", 12))
text_prelucrat.grid(column=0, row=3)
window.mainloop()
and text_local.py
from tkinter import *
class Text_Local(Text):
def __init__(self, *arg, **kwargs):
super().__init__()
def readlines(self):
new_list = []
lungime = self.index(END)
lungime_fara_ultimele_2 = lungime[:len(lungime)-2]
for index in range(1, int(lungime_fara_ultimele_2)):
element = self.get(f"{index}.0", f"{index}.0 lineend")
new_list.append(element)
return new_list
How can I resize my TextBoxes?
Thank you!
To resize a tkinter text box you change the height and width values just like you stated. The following example will change the size of the text box when you change the height and width values.
import tkinter as tk
root = tk.Tk()
root.title("Sha 256")
root.geometry("680x900")
root.config(padx=20, pady=20)
root.resizable(False, False)
text_box = tk.Text(root, height=30, width=50, font="Times 12")
text_box.grid()
root.mainloop()

Displaying frames in TKinter without classes

I'm currently writing a library system and, in order to better understand how to change between frames, have so far have written code for a screen the user is met with when they first use the program as shown below:
import tkinter as tk
import json
window = tk.Tk() # creates a window
width = 474 # sets the width and height of the screen
height = 266
screen_width = window.winfo_screenwidth() # finds the width of the user's screen
screen_height = window.winfo_screenheight()
center_x = int(screen_width / 2 - width / 2)
center_y = int(screen_height / 2 - height / 2)
window.geometry(f'{width}x{height}+{center_x}+{center_y}') # sets the width, height, and positioning of the window
window.title("Library System") # sets title of window
window.resizable(False, False) # Prevents the window being resized by both the x and y coordinates
welcome = tk.Frame(width=200, height=200, background="light cyan")
ChangeInfo = tk.Frame(window, width=400, height=200)
ChangeInfo.pack(fill='both', expand=True, padx=0, pady=0)
def WelcomeScreen():
greeting = tk.Label(welcome, text="Welcome", font=("comic sans", 15), bg ='light cyan') # creates a lable with text
greeting.pack()
explaination = tk.Label(welcome, text="This is your first time using this program so please click the button below to "
"enter in \n the username "
"and password you will be using to log into the system in the future"
"", font=("comic_sans", 9), bg="light cyan")
explaination.place(x = (width)/2, y= 50, anchor='center')
login_button = tk.Button(welcome, text="Set username and password", height=3, width=22,
font=("comic_sans", 10), bg = "turquoise")
login_button.place(x= width / 2, y= height / 2, anchor='center')
window.mainloop()
WelcomeScreen()
The only thing that is displayed at the moment is the window and its title. How do I display the frame instead of only the window?
If you want to show the welcome frame initially, you need to call welcome.pack(...) instead of ChangeInfo.pack(...).

Getting current value when dragging canvas

I am trying to make a simple card game, something like Solitaire.
I am not experienced in coding, so forgive me if it's a simple question.
I want to move some canvas objects. New objects have the right value, but when i am dragging an already existing card it shows the wrong value (waarde in Dutch). I would like to bind the value (waarde) to a card, but don't know how to do that...
Thought about tags, binding, ID....
from tkinter import *
from random import randint
window = Tk()
deck = [1,2,3,4,5,6]
def pakkaart():
rand_card = randint(0,len(deck)-1)
global waarde
waarde = deck[rand_card]
deck.pop(rand_card)
global kaart
kaart = Canvas(window, width = 40, height = 40, bg='yellow')
kaart.place(x=50, y=50, anchor=CENTER)
kaart.create_text(20,20,text=(waarde))
kaart.bind("<B1-Motion>", drag)
def drag(event):
event.widget.place(x=event.x_root, y=event.y_root,anchor=CENTER)
print(waarde)
button1 = Button(window, text="Nieuwe Kaart", command=pakkaart)
button1.pack()
window.mainloop()
So essentially looking for a way to bind a value to a canvas.
Your above code works fine, it shows the correct value, but if you want you can try this
from tkinter import *
from random import randint
window = Tk()
ws = window.winfo_screenwidth()
hs = window.winfo_screenheight()
w = 500 # width for the Tk root
h = 300 # height for the Tk root
x = (ws / 2) - (w / 2)
y = (hs / 2) - (h / 2)
window.geometry('%dx%d+%d+%d' % (w, h, x, y))
deck = [1, 2, 3, 4, 5, 6]
def pick_card():
global waarde, kaart
rand_card = randint(0, len(deck)-1)
card_number = deck[rand_card]
deck.remove(card_number)
card = Canvas(window, width=40, height=40, bg='yellow')
card.place(x=50, y=50, anchor=CENTER)
card_number_text = card.create_text(20, 20, text=card_number, tags=card_number)
card.bind("<Button-1>", lambda event: get_number(event, card_number_text)) # or you can use: card.bind("<Button-1>", lambda event: print(card_number))
card.bind("<B1-Motion>", drag)
def drag(event):
# This is better for move a widget
cx = window.winfo_pointerx() - window.winfo_rootx()
cy = window.winfo_pointery() - window.winfo_rooty()
event.widget.place(x=cx, y=cy)
def get_number(event, number):
print(event.widget.itemcget(number, "text"))
button1 = Button(window, text="Generate Card", command=pick_card)
button1.pack()
window.mainloop()
I've modified the drag(event) function and wrote two ways for get the current card value, for store it you can use some global varibles or create a class, the second would be better

How do I add label widget over my canvas in tkinter?

So I have this code which extracts new values from the database and keeps on updating on the application. The problem with it is that I need to display these values in some attractive way for which I need canvas and I'm unable to do so.
Canvas isn't working. It is not making any shapes on application. I'm sure I've made a mistake but I don't know what. Help me thanks.
Code:
import Tkinter as tk
import sqlite3
import string
import time
import sys
from constants import DELAY,DB_PATH
def update_data_for_cod_bod():
conn = sqlite3.connect('ubiqx_db.db')
c = conn.cursor()
execute_query = c.execute('''select cod,bod,tss from front_end_data
where slave_id=1''')
result_set = c.fetchall()
data_for_cod = 0
data_for_bod = 0
data_for_tss = 0
for row in result_set:
data_for_cod = row[0]
data_for_bod = row[1]
data_for_tss = row[2]
lbl_cod_data["text"] = "COD "+str(data_for_cod)
lbl_bod_data["text"] = "BOD " + str(data_for_bod)
lbl_tss_data["text"] = "TSS " + str(data_for_tss)
root.after(DELAY, update_data_for_cod_bod) # Call this function again
after DELAY ms.
def exit(event):
root.quit()
root = tk.Tk()
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.overrideredirect(1)
root.geometry("%dx%d+0+0" % (h, w))
root.title("COD_BOD")
root.configure(background='black')
root.bind("<Escape>", exit)
canvas = tk.Canvas(root, width=h, height=w, highlightthickness=0)
canvas.grid(row=0,column=0)
blackline = canvas.create_line(100, 100, 800, 100, fill="yellow")
lbl_cod_data = tk.Label(canvas, text="", font=("Times New Roman", 50,
"bold"), bg="black", fg="white")
lbl_cod_data.grid(row=0,column=0)
lbl_bod_data = tk.Label(canvas, text="", font=("Times New Roman", 50,
"bold"), bg="black", fg="white")
lbl_bod_data.grid(row=1,column=0)
lbl_tss_data = tk.Label(canvas, text="", font=("Times New Roman", 50,
"bold"), bg="black", fg="white")
lbl_tss_data.grid(row=2,column=0)
update_data_for_cod_bod() # Starts periodic calling of itself.
root.mainloop()
Actually your code is working but the canvas is covered on top by the lbl_cod_data and so you cannot see it. Try changing all .grid(...) to .place(...) like below:
canvas.place(x=0, y=0)
lbl_cod_data.place(x=50, y=100)
lbl_bod_data.place(x=50, y=200)
lbl_tss_data.place(x=50, y=300)
Then you can see the labels and the canvas together.
However, using label widgets over canvas is not a good design (for example the label widgets cannot have transparent background).
Suggest to use canvas text instead. Below is a modified code based on yours as an example:
import Tkinter as tk
import sqlite3
from constants import DELAY,DB_PATH
def update_data_for_cod_bod():
conn = sqlite3.connect('ubiqx_db.db')
c = conn.cursor()
execute_query = c.execute('''select cod,bod,tss from front_end_data where slave_id=1''')
result_set = c.fetchall()
data_for_cod = 0
data_for_bod = 0
data_for_tss = 0
for row in result_set:
data_for_cod = row[0] # do you actually want += instead?
data_for_bod = row[1]
data_for_tss = row[2]
# use itemconfig() to modify the labels text
canvas.itemconfig(lbl_cod_data, text="COD "+str(data_for_cod))
canvas.itemconfig(lbl_bod_data, text="BOD "+str(data_for_bod))
canvas.itemconfig(lbl_tss_data, text="TSS "+str(data_for_tss))
root.after(DELAY, update_data_for_cod_bod) # Call this function again after DELAY ms.
root = tk.Tk()
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.overrideredirect(1)
root.geometry("%dx%d+0+0" % (w, h)) # (h, w) in your original code
root.title("COD_BOD")
root.configure(background='black')
root.bind("<Escape>", lambda e: root.quit())
# width=h and height=w in your original code
canvas = tk.Canvas(root, width=w, height=h, highlightthickness=0, bg="dark blue")
canvas.pack()
blackline = canvas.create_line(100, 100, 800, 100, fill="yellow")
lbl_font = ("Times New Roman", 50, "bold")
lbl_cod_data = canvas.create_text(100, 100, text="COD", font=lbl_font, anchor='nw', fill="white")
lbl_bod_data = canvas.create_text(100, 180, text="BOD", font=lbl_font, anchor='nw', fill="green")
lbl_tss_data = canvas.create_text(100, 260, text="TSS", font=lbl_font, anchor='nw', fill="yellow")
update_data_for_cod_bod() # Starts periodic calling of itself.
root.mainloop()

How to clear part of a tkinter Canvas and show something when submit is pressed?

I'm creating a simple madlib style game and I've come into a bit of a problem. I cannot get the canvas to clear and show the results.
The following code places an image as the background of a canvas. It then places labels and entry fields in 2 columns for all of the words to be inserted. There is a submit button at the bottom of the page. I can't figure out how to get it clear everything except the background image, so that it can display the story, with the users words inserted. If i place it in the callback(), it clears just the background and keeps everything else. I want the opposite.
from tkinter import *
from PIL import Image, ImageTk
canvas_width = 360
canvas_height = 525
file = r"C:\Users\kraak\Desktop\PyCharm Community Edition 2017.1.2\borderedpaper.GIF"
master = Tk()
canvas = Canvas(master, width=canvas_width, height=canvas_height)
old_img = PhotoImage(file=file)
new_img = old_img.subsample(3, 3)
canvas.create_image(-11, -10, anchor=NW, image=new_img)
canvas.create_window(0, 0, height=1, width=1, anchor=NW)
canvas.create_text(0, 0, text="Test")
e1 = Entry(canvas)
canvas.create_window(250, 60, window=e1, height=15, width=100)
label = Label(text="Enter an adjective.")
label.place(x=40, y=50)
e1.focus_set()
e2 = Entry(canvas)
canvas.create_window(250, 85, window=e2, height=15, width=100)
label = Label(text="Enter a nationality.")
label.place(x=40, y=75)
e2.focus_set()
def callback():
print("Pizza was invented by a " + (e1.get()) + " " + (e2.get()))
def answer():
button = Button(text="Submit.", command=callback)
button.place(x=150, y=460)
answer()
canvas.pack()
mainloop()
As Bryan Oakley suggested you can store the id's of the widgets you want to get rid of in a list to make it easier to destroy() them all in the callback() function. Here's showing the modification to your code that would do that—note the lines with a # ADDED comments.
from tkinter import *
from PIL import Image, ImageTk
canvas_width = 360
canvas_height = 525
file = r"C:\Users\kraak\Desktop\PyCharm Community Edition 2017.1.2\borderedpaper.GIF"
master = Tk()
canvas = Canvas(master, width=canvas_width, height=canvas_height)
canvas_entry_widgets = [] # ADDED
old_img = PhotoImage(file=file)
new_img = old_img.subsample(3, 3)
canvas.create_image(-11, -10, anchor=NW, image=new_img)
canvas.create_window(0, 0, height=1, width=1, anchor=NW)
canvas.create_text(0, 0, text="Test")
e1 = Entry(canvas)
canvas.create_window(250, 60, window=e1, height=15, width=100)
label = Label(text="Enter an adjective.")
label.place(x=40, y=50)
e1.focus_set()
canvas_entry_widgets.append(e1) # ADDED
e2 = Entry(canvas)
canvas.create_window(250, 85, window=e2, height=15, width=100)
label = Label(text="Enter a nationality.")
label.place(x=40, y=75)
e2.focus_set()
canvas_entry_widgets.append(e2) # ADDED
def callback():
print("Pizza was invented by a " + (e1.get()) + " " + (e2.get()))
# destroy the canvas entry widgets and clear the list # ADDED
while canvas_entry_widgets: # ADDED
widget = canvas_entry_widgets.pop() # ADDED
widget.destroy() # ADDED
def answer():
button = Button(text="Submit.", command=callback)
button.place(x=150, y=460)
answer()
canvas.pack()
mainloop()
Every widget has a destroy method which can be used to delete the widget. In your callback you can simply call this method for every widget:
def callback():
e1.destroy()
e2.destroy()
...
In your specific case, if you want to delete all the labels you will have to give them unique names. Or, to make this even easier, you can store all of your widgets and iterate over the list.

Categories