TKinter Frame Not Filling in TopWindow - python-3.x

I'm encountering a problem. I have a root window(main window) in my code, but right now I'm creating a toplevel window for the root. I want to put a frame within a toplevel window. My problem is that I can't make the frame to fill the whole window. It only acts as a background where the widgets are placed.
def booksAvailableOpen():
## Creates a new window with all available books
global books
global backButton
books = Toplevel(root)
books.title("Available books")
books.lift(root)
books.geometry("+400+300")
books.geometry("400x400")
## Frame for toplevel window
booksFrame = ttk.Frame(books, height = 600, width = 600, relief = SUNKEN)
booksFrame.grid(row = 0, column = 0)
testLabel = ttk.Label(booksFrame,text = 'hui')
testLabel.grid(row = 0, column = 1)
## Back button used to destroy window
backButton = ttk.Button(booksFrame,text = "Go back", command = booksAvailableBackButton)
backButton.grid(row = 1, column = 1)
I also can't colour the frames, which is another issue I'm experiencing

Related

I am having trouble putting a menu bar above a Canvas widgit using tkinter

I am trying to add a menu bar on a Canvas widget. I am currently testing it using some demo code I found online, before I implement it in an application that I am writing. Currently the code shows the window, but the Menu bar appears at the bottom of the page, instead of the top.
Also more of a side note: Is there a way that I can use a function in a seperate python file to draw a shape without having it create an entire new window?
my code:
import tkinter
from tkinter import *
from tkinter import messagebox
def option():
print("Options")
top = Tk()
mb = Menubutton(top, text = "condiments", relief = RAISED)
C = Canvas(top, bg = "blue", height = 250, width = 250)
C.grid()
mb.grid()
mb.menu = Menu(mb, tearoff = 0)
mb["menu"] = mb.menu
mb.menu.add_command(label = "mayo", command = option)
mb.menu.add_command(label = "ketchup", command = option)
coord = 10,50.240, 210
coord1 = 10,50,20,60
arc = C.create_arc(coord, start = 0, extent = 150, fill = "red")
line = C.create_line(coord, fill = "white")
oval = C.create_oval(coord1, fill = "black")
top.mainloop()
By default, grid will automatically increase the row and column unless you specify otherwise. You could also simply reorder the code so that the defaults match up with your expectation.
The Zen of Python says that "explicit is better than implicit". If you explicitly define the row and column, the code will be easier to understand and you can put the menubar wherever you want.
mb.grid(row=0, column=0)
C.grid(row=1, column=0)

How can I add text and image inside a frame in Python using tkinter

I am writing my first programming codes. I want to know if I can add text and image label inside a frame. I created a canvas and added two frames to it and then tried to add image and text file (to be displayed at the top of the canvas) but the text and picture do not show. When I run the program without the frames, it does show. Here is the code:
#
from tkinter import *
from tkinter import ttk
root = Tk()
root.title ('iMedic')
canvas = Canvas(root, width = 1600, height = 800)
panewindow = ttk.Panedwindow(canvas, orient = VERTICAL)
panewindow.pack(fill = BOTH, expand = True)
paitents_frame = ttk.Frame(panewindow, width = 1600, height = 400, relief = RAISED)
prescription_frame = ttk.Frame(panewindow, width = 1600, height = 300, relief = RAISED)
panewindow.add(paitents_frame, weight = 1)
panewindow.add(prescription_frame, weight = 1)
canvas.grid(row = 0, column = 0)
photo = PhotoImage(file = './logo.gif')
canvas.create_image(55, 55, image=photo)
canvas.create_text(600, 155, text = 'Welcome', font = ('Helvetica', 72, 'bold'), justify = 'center', fill='blue')
canvas.update
root.mainloop()
#
Is there a way I can fix this? I would assume another way would be to have the pic and text on top and then add frames below it but I don't know how to do it. Thanks!
It's not clear to me why you're adding frames to a canvas but going by the later statement;
I would assume another way would be to have the pic and text on top and then add frames below it but I don't know how to do it.
Here is how you could do it:
Make the panewindow child of root instead of child of canvas
The frames resize to fit their content so I added two labels in each
to make them visible, you should replace those labels with whichever
widgets you need.
I used pack for all the widget placements but you can replace them
with grid and provide the appropriate row and column values.
**
from tkinter import *
from tkinter import ttk
root = Tk()
root.title ('iMedic')
canvas = Canvas(root, width = 1600, height = 250)
canvas.pack(fill = BOTH, expand = True)
photo = PhotoImage(file = './logo.gif')
canvas.create_image(55, 55, image=photo)
canvas.create_text(600, 155, text = 'Welcome', font = ('Helvetica', 72, 'bold'), justify = 'center', fill='blue')
canvas.update
# Make panewindow child of root
panewindow = ttk.Panedwindow(root, orient = VERTICAL)
panewindow.pack(fill = BOTH, expand = True)
# paitents_frame with Labels in it
paitents_frame = ttk.Frame(panewindow, width = 1600, height = 400, relief = RAISED)
paitents_label1 = Label(paitents_frame, text="Name Label")
paitents_label1.pack()
paitents_label2 = Label(paitents_frame, text="Name Label")
paitents_label2.pack()
# prescription_frame with Labels in it
prescription_frame = ttk.Frame(panewindow, width = 1600, height = 300, relief = RAISED)
prescription_label1 = Label(prescription_frame, text="Prescription Text")
prescription_label1.pack()
prescription_label2 = Label(prescription_frame, text="Prescription Text")
prescription_label2.pack()
# Add the frames to panewindow
panewindow.add(paitents_frame, weight = 1)
panewindow.add(prescription_frame, weight = 1)
root.mainloop()
Another option is to leave out the canvas entirely and use labels to place image and text inside a frame. See this post on how to use image in labels
This code demonstrates how to place any text on any image in a Frame.
It works by creating a Label inside the Frame to hold your image and text.
Label requires the compound attribute to be set to either bottom, center, left, right, top or none
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title ('iMedic')
photo = tk.PhotoImage(file = "./logo.gif")
frame = ttk.Frame(root, relief = tk.RAISED)
frame.grid(row = 0, column = 0, sticky = tk.NSEW)
label = tk.Label(
frame, image=photo, compound = tk.CENTER,
font = "Helvetica 40 bold",
foreground = "yellow", text = "Welcome")
label.grid(row = 0, column = 0, sticky = tk.NSEW)
root.mainloop()

Cell formatting in Grid Geometry manager

I have this code:
from tkinter import *
from tkinter import ttk
class Application:
def __init__(self, master):#Change to game class when combining code
self.master = master#remove when combining code
self.frame_Canvas = ttk.Frame(self.master, width = 600, height = 600)
self.frame_Canvas.pack(side = 'left')
self.frame_Canvas.pack_propagate(False)
self.frame_Canvas.grid_propagate(False)
self.hangman = Canvas(self.frame_Canvas, width = 600, height = 600,
background = 'white').pack()
self.FullName = ttk.Label(self.frame_Canvas, text = "Full Name", background = 'white')#full name will be entered here
self.FullName.config(font=("TkDefaultFont", 20))
self.FullName.place(x = 10, y = 10)
self.frame_Interact = ttk.Frame(self.master, width = 200, height = 600)
self.frame_Interact.pack(side = 'right')
self.frame_Interact.pack_propagate(False)
self.frame_Interact.grid_propagate(False)
self.QuestionLabel = ttk.Label(self.frame_Interact, text = "Question:")
self.QuestionLabel.config(font=("TkDefaultFont", 20))
self.QuestionLabel.grid(column = 0, row = 0)
self.QuestionShow = Text(self.frame_Interact, height=1, width=8)#input question here
self.QuestionShow.config(font=("TkDefaultFont", 20))
self.QuestionShow.grid(column = 0, row = 1)#FIX THE FORMATTING OF QUESTION, GRID CELL TO LEFT, NOT BIG ENOUGTH?
self.AnswerEntry = ttk.Entry(self.frame_Interact, width = 10)#do later
def main():
root = Tk()
root.wm_title("Hangman")
Menu = Application(root)
root.resizable(width=False, height=False)
root.iconbitmap("windowicon.ico")
root.mainloop()
if __name__ == "__main__": main()
I dont know why, but the Answer box and label on the right side of my tkinter GUI is on the left side of its frame. I want it in the center. Does anyone know a way to frix it, or any improvements for the code so far. Thanks :)
There are two ways you can do this, first way will to be to use .pack() instead of .grid() since pack is very easy to use and does the aligning for you automatically.
So you can just replace:
self.QuestionLabel.grid(column = 0, row = 0)
# and
self.QuestionShow.grid(column = 0, row = 1)
With:
self.QuestionLabel.pack()
# and
self.QuestionLShow.pack()
This way isn't recommended for your situation whatsoever, since that will involve mixing pack and grid together which could cause future errors in your code.
As Bryan Oakley said:
it will cause errors immediately, if the widgets share the same parent. It won't ever cause problems if the widgets have different parents.
You should instead do this:
from tkinter import *
from tkinter import ttk
class Application:
def __init__(self, master):#Change to game class when combining code
self.master = master#remove when combining code
self.frame_Canvas = ttk.Frame(self.master, width = 600, height = 600)
self.frame_Canvas.pack(side = 'left')
self.frame_Canvas.pack_propagate(False)
self.frame_Canvas.grid_propagate(False)
self.hangman = Canvas(self.frame_Canvas, width = 600, height = 600,
background = 'white').pack()
self.FullName = ttk.Label(self.frame_Canvas, text = "Full Name", background = 'white')#full name will be entered here
self.FullName.config(font=("TkDefaultFont", 20))
self.FullName.place(x = 10, y = 10)
self.frame_Interact = ttk.Frame(self.master, width = 200, height = 600)
self.frame_Interact.pack(side = 'right')
self.frame_Interact.pack_propagate(False)
self.frame_Interact.grid_propagate(False)
Grid.columnconfigure(self.frame_Interact, 0, weight=1) # NOTE, THIS CHANGED
self.QuestionLabel = ttk.Label(self.frame_Interact, text = "Question:")
self.QuestionLabel.config(font=("TkDefaultFont", 20))
self.QuestionLabel.grid(column = 0, row = 0)
self.QuestionShow = Text(self.frame_Interact, height=1, width=8)
self.QuestionShow.config(font=("TkDefaultFont", 20))
self.QuestionShow.grid(column = 0, row = 1)
def main():
root = Tk()
root.wm_title("Hangman")
Menu = Application(root)
root.resizable(width=False, height=False)
root.iconbitmap("windowicon.ico")
root.mainloop()
if __name__ == "__main__":
main()
By adding Grid.columnconfigure(self.frame_Interact, 0, weight=1) it will help grid know how to allocate extra space. so that the label will try to take up the whole column. The same goes for rows if you're wondering, you can add Grid.rowconfigure(self.frame_Interact, 0, weight=1) to make the widgets fill the whole row.
And for some improvements to your code, you should change this line:
self.hangman = Canvas(self.frame_Canvas, width = 600, height = 600,
background = 'white').pack()
# to
self.hangman = Canvas(self.frame_Canvas, width = 600, height = 600, background = 'white')
self.hangman.pack()
Or else self.hangman will be None, as it is in your code.

OptionMenu modify drop down list width to match OptionMenu width

Now I understand that there is already a similar question Python Tkinter: OptionMenu modify dropdown list width however this does not help me.
I am trying to make the width of the drop down menu from the OptionMenu widget responsive. Meaning that the width will always match the width of the OptionMenu. As shown in the code below, I've tried a few things but they don't apply to the submenu and it will always stay at a fixed width. Is there no way to change it?
import tkinter as tk
root = tk.Tk()
var = tk.StringVar()
var.set('First')
option = tk.OptionMenu(root, var, 'First', 'Second', 'Third')
option.configure(indicatoron = False)
option.pack(expand = True, fill = tk.X)
# Sub-menu config
submenu = option['menu']
submenu.configure(width = 50) # Can't use width
submenu.pack_configure(expand = True, fill = tk.X) # Can't use pack_configure
root.mainloop()
while there is no way to explicitly set the width, if you really must use tkinter then it is possible to add hacky workarounds to pad these things out. and example of this would be:
import tkinter as tk
from tkinter import font as tkFont
def resizer(event=None):
print("Resize")
widget = event.widget
menu = widget['menu']
req_width = widget.winfo_width()-10
menu_width = menu.winfo_reqwidth()
cur_label = menu.entrycget(0, "label")
cur_label = cur_label.rstrip() # strip off existing whitespace
font = tkFont.Font() # set font size/family here
resized = False
while not resized:
difsize = req_width - menu_width # check how much we need to add in pixels
tempsize = 0
tempstr = ""
while tempsize < difsize:
tempstr += " " # add spaces into a string one by one
tempsize = font.measure(tempstr) #measure until big enough
menu.entryconfigure(0, label=cur_label + tempstr) # reconfigure label
widget.update_idletasks() # we have to update to get the new size
menu_width = menu.winfo_reqwidth() # check if big enough
cur_label = menu.entrycget(0, "label") # get the current label for if loop needs to repeat
if menu_width >= req_width: # exit loop if big enough
resized = True
root = tk.Tk()
var = tk.StringVar()
var.set('First')
option = tk.OptionMenu(root, var, 'First', 'Second', 'Third')
option.bind("<Configure>", resizer) # every time the button is resized then resize the menu
option.configure(indicatoron = False)
option.pack(expand = True, fill = tk.X)
root.mainloop()
this essentially just pads out the first menu item until the menu is big enough. however there does seem to be some discrepancy in the widths reported back by tkinter hence my req_width = widget.winfo_width()-10 offset near the top.
however this will not always be a perfect match size wise, while testing my a space seems to take 3 pixels of width, so it could be 1 or 2 pixels out at any time.

Set a background image for my window

I just wondering what I should do to apply an image as background of my tkinter window.
I want this window with a gif image in the background and a few buttons on top of it..
the error msg says: "x.image = bg_image.grid(row = 0, column = 0)
AttributeError: 'PhotoImage' object has no attribute 'grid'"
do I need to import something else?
whats wrong? I dont even know if this PhotoImage code is supported by this version of python (python 3.1.1)...
from tkinter import*
window = Tk()
window.title("ksdasndsnadn")
bg_image = PhotoImage(file ="pic.gif")
x = Label (image = bg_image)
x.image = bg_image.grid(row = 0, column = 0)
window.geometry("600x300")
app = Application(window)
window.mainloop()
You need to apply the grid method to the label that contains the image, not the image object:
bg_image = PhotoImage(file ="pic.gif")
x = Label (image = bg_image)
x.grid(row = 0, column = 0)
http://effbot.org/tkinterbook/photoimage.htm

Resources