This question already has answers here:
Why does Tkinter image not show up if created in a function?
(5 answers)
Closed 5 months ago.
It's my first post here, I also have a puzzlement about the code below.
I don't have the image displayed next to the text, the button is properly displayed (p.s : why the height and width have to be adjusted again, for example the button without the picture has width = 22 and height = 2, when I put the picture to be visible I have 200 by 200, well it can be a bit smaller), I have the text displayed, but the picture is missing...Could it be from .grid?
bl_logo = Image.open('img/balance.png')
bl_logo = bl_logo.resize((25,25), Image.ANTIALIAS)
balance_img = ImageTk.PhotoImage(bl_logo)
buttons_frame = tk.Frame(main_frame, bg = "#004d4d")
balance_btn = tk.Button(buttons_frame, image = balance_img, compound = tk.LEFT, text = 'BALANCE', font = ('Bebas NEUE', 20), width = 220, height = 200)
balance_btn.grid(row = 0, column = 0, sticky = tk.W, padx = 10, pady = (60,40)
You have to save the balance_img in the widget class to prevent it from the garbage collector.
add this line balance_btn.image = balance_img
bl_logo = Image.open('img/balance.png')
bl_logo = bl_logo.resize((25,25), Image.ANTIALIAS)
balance_img = ImageTk.PhotoImage(bl_logo)
buttons_frame = tk.Frame(main_frame, bg = "#004d4d")
balance_btn = tk.Button(buttons_frame, image = balance_img, compound = tk.LEFT, text = 'BALANCE', font = ('Bebas NEUE', 20), width = 220, height = 200)
balance_btn.image = balance_img
balance_btn.grid(row = 0, column = 0, sticky = tk.W, padx = 10, pady = (60,40)
I already answer this question's answer to another user.
Related
I am making an F1 drivers' application, which gathers API data. The application has designated labels for where specific API content needs to be placed.
What's happening is that whenever I put anything beside a designated label through .grid, the distance between whatever I put and the label is too big. A perfect example of this is in the bottom_left_frame. I've tried different ways (i.e, sticky, padding), but no luck. One way that seems to work is .configure(), but I don't think it's a scalable solution, and I want to place my objects through .grid()
Here's the code. Would appreciate the help!
#import necessary modules
from tkinter import *
from tkinter import ttk
from PIL import ImageTk, Image
from tkinter import messagebox
import requests
import json
root = Tk()
root.title("F1 Desktop Application")
root.geometry("500x600")
root.configure(bg="white")
#NEED TO UNDERSTAND PRECEDENCE BETWEEN WIDTH, HEIGHT SETTING, VS SPANS. STICKY MAKES PERFECT SENSE
top_frame = LabelFrame(root, width = 300, height = 125)
top_frame.grid(row = 0, column = 0, columnspan = 2)
top_frame.rowconfigure(0, minsize = 75)
top_frame.columnconfigure(0, minsize = 300)
header_label = Label(top_frame, text = "F1 2022 Drivers App", font = ("Arial bold",14), bg = "white")
header_label.grid(row = 0, column = 0)
entry= Entry(top_frame)
entry.grid(row = 1, column = 0)
#search_button = Button(top_frame, text = "search")
#search_button.grid(row = 1, column = 1)
left_frame = LabelFrame(root, width = 250, height = 225, borderwidth = 0, highlightthickness = 2)
left_frame.grid(row = 1, column = 0, sticky = NW, padx = 10, pady = 15)
#left_frame.grid_propagate(False)
left_frame.rowconfigure(0, minsize = 100)
left_frame.columnconfigure(0, minsize = 200)
#left_frame_content = LabelFrame(, width = 125, height = 70)
#left_frame_content.grid(row = 1, column = 1, sticky = W)
basic_info = Label(left_frame, text = "Basic Info ", font = ("Arial bold",14))
basic_info.grid(row = 0, column = 0)
full_name = Label(left_frame, text = "Full Name :")
full_name.grid(row = 1, column = 0, sticky = W)
driver_code = Label(left_frame, text = "Driver Code : ")
driver_code.grid(row = 2, column = 0, sticky = W)
nationality = Label(left_frame, text = "Nationality : ")
nationality.grid(row = 3, column = 0, sticky = W)
bottom_left_frame = LabelFrame(root, width = 250, height = 225)
bottom_left_frame.grid(row = 2, column = 0, sticky = N, padx = 10)
bottom_left_frame.rowconfigure(0, minsize = 25)
bottom_left_frame.columnconfigure(0, minsize = 200)
F1_career = Label(bottom_left_frame, text = "F1 Career ", font = ("Arial bold",14))
F1_career.grid(row = 0, column = 0)
wins = Label(bottom_left_frame, text = "Wins :")
wins.grid(row = 1, column = 0, sticky = W)
wins.configure(text = "Wins :" + " 7")
poles = Label(bottom_left_frame, text = "Poles :")
poles.grid(row = 2, column = 0, sticky = W)
test = Label(bottom_left_frame, text = "test")
test.grid(row = 2, column = 1)
podiums = Label(bottom_left_frame, text = "Podiums :")
podiums.grid(row = 3, column = 0, sticky = W)
drivers_championships = Label(bottom_left_frame, text = "Championships :")
drivers_championships.grid(row = 4, column = 0, sticky = W)
bottom_right_frame = LabelFrame(root, width = 250, height = 225)
bottom_right_frame.grid(row = 2, column = 1, sticky = W)
bottom_left_frame.rowconfigure(0, minsize = 50)
bottom_left_frame.columnconfigure(0, minsize = 150)
root.mainloop()
This question already has answers here:
Why does Tkinter image not show up if created in a function?
(5 answers)
Closed 6 months ago.
I'm trying to display a frame with a canvas inside in order I'll be able to change of frame with a button, but when the code is executed it does not even display the button, I don't know if it happens because of all is on a function, if doing what I think is even possible or if I'm missing something
from tkinter import *
window = Tk()
window.geometry("1200x700")
window.configure(bg = "#ffffff")
def btn_clicked():
print("Button Clicked")
frame1 =Frame(window, width=1200, height=700)
frame1.grid(row=0, column=0)
def load_page():
frame1.tkraise()
frame1.pack_propagate(False)
canvas = Canvas(
frame1,
bg = "#263ff8",
height = 700,
width = 1200,
bd = 0,
highlightthickness = 0,
relief = "ridge")
canvas.place(x = 0, y = 0)
background_img = PhotoImage(file = f"background.png")
background = canvas.create_image(
601.0, 341.0,
image=background_img)
img0 = PhotoImage(file = f"img0.png")
boton = Button(
image = img0,
borderwidth = 0,
highlightthickness = 0,
command = btn_clicked,
relief = "flat")
boton.place(
x = 85, y = 71,
width = 430,
height = 99)
load_page()
window.resizable(False, False)
window.mainloop()
Rephrased the entire code and including image:
To see button display. I had to reduced height and width in Canvas. Also The button had to reduced. In line 21, I changed bd = 10. You can comment in , because I don't used PhotoImage. you can debug see in image.
from tkinter import *
window = Tk()
window.geometry("1200x700")
window.configure(bg = "#ffffff")
def btn_clicked():
print("Button Clicked")
frame1 =Frame(window, width=1200, height=700)
frame1.grid(row=0, column=0)
def load_page():
frame1.tkraise()
frame1.pack_propagate(False)
canvas = Canvas(
frame1,
bg = "#263ff8",
height = 100,
width = 200,
bd = 10,
highlightthickness = 0,
relief = "ridge")
canvas.place(x = 0, y = 0)
#background_img = PhotoImage(file = f"background.png")
#background = canvas.create_image(
#601.0, 341.0,
#image=background_img)
#img0 = PhotoImage(file = f"img0.png")
boton = Button(frame1,
#image = img0,
borderwidth = 0,
highlightthickness = 0,
command = btn_clicked,
relief = "flat")
boton.place(
x = 85, y = 71,
width = 30,
height =29)
load_page()
window.resizable(False, False)
window.mainloop()
Output result. you can see debug.
I have an app that has a frame which houses a gridview of information regarding product data. I want frame3 to have a static window size with a scroll bar. The scroll bar, not implemented yet, will allow the user to scroll down to see the remaining product data not visibly seen inside the static window.
My problem is that frame3 as of right now, doesn't seem to have a visible, static frame size. It just looks like it takes up one row in my overall app gridview, as seen in the picture:
picture of current program
I would like the "Bar Code - Product Description ..." section to acquire most of the screen real-state of the app but i can't seem to get it to work. I've tried creating a canvas inside frame3 but it still doesn't work.
Any ideas?
The code below is just a short snippet of my overall application
frame3 = Frame(self, bg = "black", width = 690, height = 400, borderwidth = 1)
frame3.pack()
frame3Label1 = tk.Label(frame3, text="Bar Code", font=NORMAL_FONT, relief = SUNKEN, width = 16)
frame3Label1.grid(row = 0, column = 0)
frame3Label2 = tk.Label(frame3, text="Product Description", font=NORMAL_FONT, relief = SUNKEN, width = 30)
frame3Label2.grid(row = 0, column = 1)
frame3Label3 = tk.Label(frame3, text="Price", font=NORMAL_FONT, relief = SUNKEN, width = 10)
frame3Label3.grid(row = 0, column = 2)
frame3Label4 = tk.Label(frame3, text="Quantity", font=NORMAL_FONT, relief = SUNKEN, width = 8)
frame3Label4.grid(row = 0, column = 3)
frame3Label5 = tk.Label(frame3, text="Discount", font=NORMAL_FONT, relief = SUNKEN, width = 8)
frame3Label5.grid(row = 0, column = 4)
frame3Label6 = tk.Label(frame3, text="Cost", font=NORMAL_FONT, relief = SUNKEN, width = 10)
frame3Label6.grid(row = 0, column = 5)
#Function that creates more labels/entry boxes under these static existing labels
frame3.pack(expand=True)
I just used the expand property as per mentioned in a comment
Currently, I'm preforming the following code to delete the child widgets on the gui
for child in infoFrame.winfo_children():
child.destroy()
However, the gui will not add another child to the gui. For example, neither lines of the following code
people.place(in_ = gui, x = 1, y = 1, width = 422, height = 449)
people.grid(row = 0, column = 0)
place a label on the gui. I'm using the following code to create the label
people = Label(text = "Default", fg = "black", bg = "white")
EDIT I was asked to add my gui code, so here it is:
def initializeGui(name = "Default"):
GUI = Tk()
GUI.geometry("423x450+200+200")
GUI.title(name)
return GUI
def buttonAnswers(): #This is what I'm focusing on
gui.title("Answers")
for child in gui.winfo_children():
child.destroy()
return True
people = Label(text = "Default", fg = "black", bg = "white")
#people.place(in_ = gui, x = 1, y = 1, width = 422, height = 449)
people.grid(row = 0, column = 0)
def buttonTest(): #This will be the same as the button above but will open a different gui
gui.title("Test")
for child in gui.winfo_children():
child.destroy()
return True
question = Label(text = "Do you want to see the Answers or take the Test?", fg = "black", bg = "white")
question.grid(row = 0, column = 1)
checkAns = Button(gui, text = "Answers", command = buttonAnswers, fg = "black", width=10)
checkAns.grid(row = 1, column = 0)
gui = initializeGui("School Test")
label = Label(text = "Do you want to see the Answers or take the Test?", fg = "black", bg = "white")
label.grid(row = 0, column = 1)
answers = Button(gui, text = "Answers", command = buttonAnswers, fg = "black", width=10)
questions = Button(gui, text = "Test", command = buttonTest, fg = "black", width=10)
answers.grid(row = 1, column = 0)
questions.grid(row = 1, column = 2)`
The solution to the issue was the following:
def buttonAnswers(): #This is what I'm focusing on
gui.title("Answers")
for child in gui.winfo_children():
child.destroy()
return True
people = Label(text = "Default", fg = "black", bg = "white")
#people.place(in_ = gui, x = 1, y = 1, width = 422, height = 449)
people.grid(row = 0, column = 0)
contained a return True underneath the for loop, preventing the program from continuing. As such, removing the return True allowed the program to continue with the script and add the other children to the form.
def buttonAnswers(): #This is what I'm focusing on
gui.title("Answers")
for child in gui.winfo_children():
child.destroy()
people = Label(text = "Default", fg = "black", bg = "white")
#people.place(in_ = gui, x = 1, y = 1, width = 422, height = 449)
people.grid(row = 0, column = 0)
You have a return statement after you destroy the widgets but before you add any new widgets. The code to add the new widgets is never getting executed.
When i put widgets inside my canvas, the widgets bypass the canvas size. But when I scroll, the canvas won't move.
On top of that, the canvas auto re-sizes when I add more widgets. I thought the canvas isn't supposed to re-size because I already added a scroll bar?
Here's my code:
from tkinter import *
from tkinter import ttk
import mysql.connector
class CanvasScroll:
def on_resize(self,event):
self.canvas.config(width = 1185, height = 530)
def add_crew(self):
crewFrame = CrewFrame()
def callback_list(self):
index = self.notebook.index(self.notebook.select()) + 1
self.tmpframe = Try2(self.contentframe, index)
def __init__(self, master):
self.canvas = Canvas(master, width = 1185, height = 530, scrollregion = (0, 0, 1216, 700), bg = 'white', confine = True)
self.canvas.grid(row = 2, column = 0, sticky = 'news')
self.xscroll = ttk.Scrollbar(master, orient = HORIZONTAL, command = self.canvas.xview)
self.xscroll.grid(row = 3, column = 0, sticky = 'we')
self.yscroll = ttk.Scrollbar(master, orient = VERTICAL, command = self.canvas.yview)
self.yscroll.grid(row = 2, column = 1, sticky = 'ns')
self.canvas.config(xscrollcommand = self.xscroll.set, yscrollcommand = self.yscroll.set)
self.canvas.bind("<Configure>", self.on_resize)
self.option = ttk.Frame(master, height = 150, width = 1206)
self.option.grid(row = 0, column = 0, sticky = 'we', columnspan = 5)
self.addicon = PhotoImage(file = 'C:\\Users\\rain\\Desktop\\Fyosh!\\logo\\add.gif').subsample(2,2)
self.btnAdd = ttk.Button(self.option, image = self.addicon, text = 'Add Crew', compound = TOP, command = self.add_crew)
self.btnAdd.grid(row = 0, column = 0, padx = 50, pady = 5)
self.updateicon = PhotoImage(file = 'C:\\Users\\rain\\Desktop\\Fyosh!\\logo\\update.gif').subsample(2,2)
self.btnUpdate = ttk.Button(self.option, image = self.updateicon, text = 'Update Crew', compound = TOP)
self.btnUpdate.grid(row = 0, column = 1, padx = 50)
self.deleteicon = PhotoImage(file = 'C:\\Users\\rain\\Desktop\\Fyosh!\\logo\\delete.gif').subsample(2,2)
self.btnDelete = ttk.Button(self.option, image = self.deleteicon, text = 'Delete Crew', compound = TOP)
self.btnDelete.grid(row = 0, column = 2, padx = 50)
self.reloadicon = PhotoImage(file = 'C:\\Users\\rain\\Desktop\\Fyosh!\\logo\\Refresh.png').subsample(7,7)
self.reloadbtn = ttk.Button(self.option, image = self.reloadicon, command = self.callback_list, text = 'Load List', compound = TOP)
self.reloadbtn.grid(row = 0, column = 3, padx = 50)
self.tabframe = ttk.Frame(master, height = 20)
self.tabframe.grid(row = 1, sticky = 'we')
self.notebook = ttk.Notebook(self.tabframe)
self.notebook.grid(row = 0, column = 0, sticky = 'we')
db = mysql.connector.connect(user = 'root', password = '', host = 'localhost', database = 'fat2x_payroll')
cursor = db.cursor()
ships = ("SELECT * from tbl_shiplist")
try:
cursor.execute(ships)
result = cursor.fetchall()
self.tab = {}
for row in result:
self.tab[row[0]] = {
"shipname": ttk.Frame(self.notebook)
}
self.notebook.add(self.tab[row[0]]["shipname"], text = row[1])
db.close()
except:
messagebox.showinfo("alert", "ship list error")
self.canvas.label = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 0)
self.canvas.label1 = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 1)
self.canvas.label2 = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 2)
self.canvas.label3 = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 3)
self.canvas.label4 = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 4)
self.canvas.label5 = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 5)
self.canvas.label6 = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 6)
self.canvas.label7 = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 7)
self.canvas.label8 = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 8)
def start():
master = Tk()
master.geometry("1206x690+10+10")
master.resizable(0,0)
master.title("Crew Panel")
canvasScroll = CanvasScroll(master)
if __name__ == "__main__":
start()
The canvas can only scroll objects that are embedded on the canvas. In the case of widgets, that means that you've called the create_window method of the canvas for the widgets you want to be affected by the scrollbar.
If you want to use grid to organize widgets, and you want those widgets to be in a scrollable container, the usual method is to put those widgets inside a frame, and then add the frame to the canvas with create_window. You can see an example of this technique in this answer: https://stackoverflow.com/a/3092341/7432
As for the auto-resize, this behavior is completely unrelated to using a scrollbar. If you use grid or pack on a widget, the parent will always resize unless you've turned geometry propagation off. It doesn't matter if it's a Canvas or a Frame or a Toplevel, or any other class of widget.