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()
Related
I want my Tkinter window to have four buttons, each with its own background image, disposed as a 2x2 grid. I tried using frames but you can't set an image as frame background so I had to switch to Canvas. This is the code for one of the four blocks.
from tkinter import *
from PIL import ImageTk, Image
root = Tk()
root.geometry("500x200")
root.wm_title("KnowYourArt")
styles_bg = ImageTk.PhotoImage(Image.open("images/styles_bg.png"))
canvas_styles = Canvas(root)
bg = canvas_styles.create_image(100, 100, image=styles_bg)
width = 4
height = 2
Button(canvas_styles, text="Styles", width=width, height=height).pack(side=TOP)
Label(canvas_styles, text="Gain info about styles").pack(side=BOTTOM)
canvas_styles.grid(row=0, column=0)
This is the output I get:
In my intentions, the background image dimensions should cover both the button and the label, and the image's dimensions should be independent from the dimensions of the widgets. Instead, I obtain a canvas where the height of the BG image is the same as the height of the button, and the width is the same as the label's width. I tried many alternative possibilities, including setting a width and height for the canvas, and none of them properly worked. What am I doing wrong?
I managed to find a solution. Here is the code:
from tkinter import *
from PIL import ImageTk, Image
width = 4
height = 1
def add_canvas(frame, img, x, y, text):
c = Canvas(frame, width=300, height=300)
c.focus()
c.pack(fill=BOTH, expand=True)
bg = c.create_image(x, y, image=img)
btn = Button(frame, text="Go!", width=width, height=height)
c.create_text(150, 190, text=text, font=('Helvetica', 15), fill='white')
c.create_window(100, 200, anchor="nw", window=btn)
return c
root = Tk()
root.geometry("600x600")
root.wm_title("Title")
f_1 = Frame(root)
f_2 = Frame(root)
f_3 = Frame(root)
f_4 = Frame(root)
bg1 = ImageTk.PhotoImage(Image.open("images/im1.png"))
bg2 = ImageTk.PhotoImage(Image.open("images/im2.png"))
bg3 = ImageTk.PhotoImage(Image.open("images/im3.png"))
bg4 = ImageTk.PhotoImage(Image.open("images/im4.jpg"))
canvas_1 = add_canvas(f_1, bg1, 0, 0, "foo")
canvas_2 = add_canvas(f_2, bg2, 240, 240, "foo")
canvas_3 = add_canvas(f_3, bg3, 120, 120, "foo")
canvas_4 = add_canvas(f_4, bg4, 100, 100, "foo")
f_1.grid(row=0, column=0)
f_2.grid(row=0, column=1)
f_3.grid(row=1, column=0)
f_4.grid(row=1, column=1)
And here's the output
I have a hard time implementing a scrollbar into my Tkinter project. I've been through numerous articles and answered questions on how to implement a scrollbar, but I'm just unable to implement a working solution after an entire day of researching this one 'simple' matter.
My current code looks like this:
import tkinter as tk
from tkinter import Button, ttk
from PIL import ImageTk, Image
from functools import partial
import queue as qu
import math
import re
import os
window = tk.Tk()
queue = qu.Queue()
#Basic values
#the window size
windowSize = "700x1000"
#picture and container size
x, y = 200, 300
#tmp
sidepanelsize = 200
window.geometry(windowSize)
#button identifier
def change(i):
print(I)
#temporary content generator
for g in range(12):
for item in os.listdir("."):
if re.search(r"\.(jpg|png)$", item):
queue.put(item)
n = queue.qsize()
#other panels that are going to be used later
frameLeft = tk.Frame(master=window, width=sidepanelsize, relief=tk.RIDGE)
frameLeft.pack(fill=tk.Y, side=tk.LEFT)
label1 = tk.Label(master=frameLeft, text="Left Panel")
label1.pack()
buttonLeft1 = tk.Button(master=frameLeft, text="Button 1", command=lambda: print("I'm a side button!"))
buttonLeft1.pack()
frameMain = tk.Frame(master=window, relief=tk.GROOVE, borderwidth=1)
frameMain.pack(side=tk.TOP, fill=tk.X, expand=1)
# SCROLLBAR IF YOU DISABLE THIS SECTION AND PUTS SOME PICTURES IN THE FOLDER WHITH THE FILE THE CODE WORKS #
myCanvas = tk.Canvas(master=frameMain)
myCanvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
myScrollbar = ttk.Scrollbar(master=frameMain, orient=tk.VERTICAL, command=myCanvas.yview)
myScrollbar.pack(side=tk.RIGHT, fill=tk.Y)
myCanvas.configure(yscrollcommand=myScrollbar.set)
myCanvas.bind('<Configure>', lambda e: myCanvas.configure(scrollregion=myCanvas.bbox("all")))
secondFrame = tk.Frame(master=myCanvas)
myCanvas.create_window((0, 0), window=secondFrame, anchor=tk.NW)
############################ END OF SCROLLBAR ############################
noOfImgPerRow = math.floor((int(windowSize.split("x")[0])-sidepanelsize+100)/x)
imgs = []
#generates the grid
for i in range(n):
o = i
i = (o % noOfImgPerRow) + 1
j = math.floor(o/noOfImgPerRow) + 1
frameMain.columnconfigure(i, weight = 1, minsize=x+15)
frameMain.rowconfigure(i, weight = 1, minsize=y+50)
frameBox = tk.Frame(
master=frameMain,
relief=tk.RAISED,
borderwidth=1,
width = x,
height = y
)
# here the error references to
frameBox.grid(row=j, column=i, padx=5, pady=5)
img = Image.open(queue.get()).convert("RGBA")
width, height = img.size
if width/x >= height/y:
left = width/2-(round((height*x)/y))/2
right = width/2+(round((height*x)/y))/2
upper = 0
lower = height
else:
left = 0
right = width
upper = height/2-(round((width*y)/x))/2
lower = height/2+(round((width*y)/x))/2
img2 = img.crop([left, upper, right, lower])
img2 = img2.resize((x, y), Image.Resampling.LANCZOS)
imgs.append(ImageTk.PhotoImage(img2))
label = tk.Label(master = frameBox, image = imgs[-1])
label.pack()
mainButton = Button(master=frameBox, text="Start", command=partial(change, o))
mainButton.pack()
window.mainloop()
I've tried to highlight the only thing of concern, that being the scrollbar, everything else is working at the moment, I just wanted to post the whole code for better understanding if it would help in any way.
My problem is whenever I implement the scrollbar, it throws back an error stating:
Traceback (most recent call last):
File "e:\Python\starter\main.py", line 85, in <module>
frameBox.grid(row=j, column=i, padx=5, pady=5)
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.1264.0_x64__qbz5n2kfra8p0\lib\tkinter\__init__.py", line 2522, in grid_configure
self.tk.call(
_tkinter.TclError: cannot use geometry manager grid inside .!frame2 which already has slaves managed by pack
This error seems pretty self-explanatory, just grid the canvas instead of packing it, but when after a lot of small tweaking and doing things a roundabouts things
My second thought was if it has a problem with the grid to wrap the gridded frame in another bigger packed frame, like so:
yetAnotherFrame = tk.Frame(frameMain)
yetAnotherFrame.pack()
noOfImgPerRow = math.floor((int(windowSize.split("x")[0])-sidepanelsize+100)/x)
imgs = []
for i in range(n):
o = i
i = (o % noOfImgPerRow) + 1
j = math.floor(o/noOfImgPerRow) + 1
yetAnotherFrame.columnconfigure(i, weight = 1, minsize=x+15)
yetAnotherFrame.rowconfigure(i, weight = 1, minsize=y+50)
frameBox = tk.Frame(
master=yetAnotherFrame,
relief=tk.RAISED,
borderwidth=1,
width = x,
height = y
)
frameBox.grid(row=j, column=i, padx=5, pady=5)
This actually runs to my surprise, but the scrollbar still isn't working and the layout is broken again.
Solution
In your code frameBox's parent is frameMain. Instead you need to have the canvas as parent or the secondFrame which have the canvas as its parent.
Example
This is basically your code with fixes, but some of the unnecessary parts are removed.
import tkinter as tk
from tkinter import ttk
window = tk.Tk()
window.geometry("400x400")
frameLeft = tk.Frame(master=window, width=400, height=400, relief=tk.RIDGE)
frameLeft.pack(fill=tk.Y, side=tk.LEFT)
myCanvas = tk.Canvas(master=frameLeft)
myCanvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
myScrollbar = ttk.Scrollbar(master=frameLeft, orient=tk.VERTICAL, command=myCanvas.yview)
myScrollbar.pack(side=tk.RIGHT, fill=tk.Y)
myCanvas.configure(yscrollcommand=myScrollbar.set)
myCanvas.bind('<Configure>', lambda e: myCanvas.configure(scrollregion=myCanvas.bbox("all")))
secondFrame = tk.Frame(master=myCanvas)
myCanvas.create_window((0, 0), window=secondFrame, anchor=tk.NW)
for i in range(100):
lbl = tk.Label(secondFrame, text=f"Label {i}")
lbl.grid(column=0, row=i, sticky=tk.W)
window.mainloop()
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()
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()
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.