Cell formatting in Grid Geometry manager - python-3.x

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.

Related

How can I scroll multiple frames in canvas?

I want to create a list of frames with further features like a button, label e.g.. but my issues are the size of the LabelFrame. If I put the LabelFrame in container it fits like I want to but it isn't scrollable any more. Any ideas?
from tkinter import ttk
import tkinter as tk
root = tk.Tk()
container = ttk.Frame(root)
canvas = tk.Canvas(container)
scrollbar = ttk.Scrollbar(container, orient="vertical", command=canvas.yview)
scrollable_frame = ttk.Frame(canvas)
scrollable_frame.bind(
"<Configure>",
lambda e: canvas.configure(
scrollregion=canvas.bbox("all")
)
)
canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
canvas.configure(yscrollcommand=scrollbar.set)
for i in range(50):
lf = ttk.Frame(scrollable_frame, text=i).grid(column=1, row=i)
frame_ip = tk.LabelFrame(lf, bg="white", text=i)
frame_ip.place(relwidth=0.95, relheight=0.2, relx=0.025, rely=0)
button_scroll1 = tk.Button(frame_ip, text="Start", bg="grey")
button_scroll1.place(relwidth=0.15, relx=0.025, relheight=0.15, rely=0.1)
container.pack()
canvas.pack(side="left", fill="both", expand=True)
scrollbar.pack(side="right", fill="y")
root.mainloop()
Here is your updated code with a Button, Canvas and Scrollbar inserted into each LabelFrame with grid manager.
I've also made the container resizable with row|column configure.
Seems to work fine.
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.rowconfigure(0, weight = 1)
root.columnconfigure(0, weight = 1)
root.geometry("341x448")
container = ttk.Frame(root)
container.rowconfigure(0, weight = 1)
container.columnconfigure(0, weight = 1)
canvas = tk.Canvas(container)
scrollbar = ttk.Scrollbar(container, orient = tk.VERTICAL, command = canvas.yview)
scrollable_frame = ttk.Frame(canvas)
scrollable_frame.bind(
"<Configure>",
lambda e: canvas.configure(
scrollregion=canvas.bbox("all")))
canvas.create_window((0, 0), window = scrollable_frame, anchor = tk.NW)
canvas.configure(yscrollcommand = scrollbar.set)
for i in range(15):
L = ttk.LabelFrame(scrollable_frame, text = "Sample scrolling label")
L.grid(row = i, column = 0, sticky = tk.NSEW)
B = ttk.Button( L, text = f"Button {i}")
B.grid(row = 0, column = 0, sticky = tk.NW)
K = tk.Canvas(
L, width = 300, height = 100,
scrollregion = "0 0 400 400", background = "#ffffff")
K.grid(row = 1, column = 0, sticky = tk.NSEW)
S = ttk.Scrollbar( L, command = K.yview)
S.grid(column = 1, row = 1, sticky = tk.NSEW)
K["yscrollcommand"] = S.set
container.grid(row = 0, column = 0, sticky = tk.NSEW)
canvas.grid(row = 0, column = 0, sticky = tk.NSEW)
scrollbar.grid(row = 0, column = 1, sticky = tk.NS)
root.mainloop()

tkinter scrollbar with grid, it doesn't get linked

I'm studying GUI, so please understand my poor codes below.
I was trying to make a program which gets game-character's information. So if you press the 'search' button, the list would be shown below. But... it only shows about 11 names due to the window size. So i wanted to put a scrollbar for that area, but I just don't know how to link the scroll bar to control the area. I meant, the scroll bar itself has created, and it does scroll itself, but it doesn't scroll the window I wanted. I must have linked it wrong but... not sure.
Below is the minimized example code, but it's still quite long and crude. Sorry for that again.
If anyone can enlighten me, it would be really great help for this and my future works as well.
import tkinter as tk
import requests
from bs4 import BeautifulSoup
import webbrowser
import time
global var_dict, input_id, output
var_dict = {}
def enter_call_back(event=None):
output.grid(column = 0, row = 2, columnspan = 5 , sticky='w')
output.insert(tk.END,"Text_Something")
output.update()
search_chr()
def open_browse(url_list):
for url in url_list:
time.sleep(0.3)
webbrowser.open(url)
def search_inven(ch_id):
if ch_id == "ch1" or ch_id == "ch13" or ch_id == "ch15" :
num = 5
url_list = ["something.url","something2.url"]
self_count = 1
else:
num = 0
url_list = []
self_count = 0
masterset = []
masterset.append(num)
masterset.append(url_list)
masterset.append(self_count)
return masterset
def search_chr():
global var_dict, output
for things in var_dict.keys():
var_dict[things].destroy()
chr_list = ["ch1","ch2","ch3","ch4","ch5","ch6","ch7","ch8","ch9","ch9","ch10","ch11","ch12","ch13","ch14","ch15"]
output.insert(tk.END," Done! \n\n")
var_dict = {}
num = -1
for ch in chr_list:
num += 1
var_dict["output%s" %num] = tk.Entry(frame_buttons, width = 125)
result = search_inven(ch)
if result[0] == 0:
var_dict["output"+str(num)].insert(0, "Clean "+ch+"\n")
var_dict["output"+str(num)].grid(column = 0, row = num, sticky='w', padx=5, pady=5)
else:
url_list = result[1]
var_dict["o-button%s" %num] = tk.Button(frame_buttons, command=lambda url_list = url_list : open_browse(url_list))
var_dict["o-button"+str(num)].grid(column = 1, row = num, sticky='e')
var_dict["o-button"+str(num)].config(text="URL")
var_dict["output"+str(num)].insert(0, "Not Clean "+str(result[0])+" Self : "+str(result[2])+" Ch_id : "+ch+")\n")
var_dict["output"+str(num)].grid(column = 0, row = num, sticky='w', padx=5, pady=5)
vsb = tk.Scrollbar(frame_canvas, orient="vertical")
vsb.grid(row=0, column=1, sticky='ns')
vsb.config(command=canvas.yview)
canvas.configure(yscrollcommand=vsb.set)
frame_canvas.config(height = 300)
canvas.config(scrollregion=canvas.bbox("all"))
root = tk.Tk()
root.geometry("760x710")
root.resizable(width=False, height=False)
root.title("Minimum v.1.2")
root.grid_rowconfigure(0, weight=1)
root.columnconfigure(0, weight=1)
frame_main = tk.Frame(root, bg="gray")
frame_main.grid(sticky='news')
intro = tk.Text(frame_main, height = 17, bg="#E3D5F3")
intro.option_add("*Font", "명조 10")
intro.insert(tk.CURRENT,"Text_something")
intro.config(state='disabled')
intro.grid(row=0, column=0, pady=(5, 0), columnspan = 5, sticky='nw')
input_id = tk.Entry(frame_main, width = 35)
input_id.option_add("*Font","명조 10")
input_id.insert(0,"Ch_name")
input_id.grid(row=1, column=0, pady=(5, 0), sticky='w')
search_btn = tk.Button(frame_main)
search_btn.config(text="Search")
search_btn.option_add("*Font","명조 10")
search_btn.config(width=5,height=1)
search_btn.grid(row = 1, column = 0, pady=(5, 0), sticky='e')
output = tk.Text(frame_main, height = 10)
output.option_add("*Font","명조 10")
output.grid(row = 2, column = 0,pady=(5,0),sticky='nw')
frame_canvas = tk.Frame(frame_main, width = 565)
frame_canvas.grid(row=3, column=0, pady=(5, 0), columnspan = 3 ,sticky='nw')
frame_canvas.grid_rowconfigure(0, weight=1)
frame_canvas.grid_columnconfigure(0, weight=1)
frame_canvas.grid_propagate(False)
canvas = tk.Canvas(frame_canvas, bg="gray", height=500,scrollregion=(0,0,500,1800))
canvas.grid(row=0, column=0, sticky="news")
frame_buttons = tk.Frame(canvas, bg="gray")
frame_buttons.grid(row = 0, column = 0,sticky='e')
root.bind('<Return>',enter_call_back)
search_btn.config(command = enter_call_back)
root.mainloop()
First, using grid() to put frame_buttons into the canvas will not affect the scrollregion of the canvas. Use canvas.create_window() instead.
Second, it is better to bind <Configure> event on frame_buttons and update canvas' scrollregion inside the bind callback. Then adding widgets to frame_buttons will automatically update the scrollregion.
Also note that you have created new scrollbar and put it at same position whenever search_chr() is executed. Better create the scrollbar only once outside the function.

Im having troubles with python(tkinter) gui with the layout

# Import module
from tkinter import *
import pyautogui, time
# Create object
root = Tk()
# Adjust size
root.geometry("350x350")
root.title("SycoBak's SpamBot")
# Add image file
bg = PhotoImage(file = "Slogo.png")
# Create Canvas
canvas1 = Canvas( root, width = 350,
height = 350)
canvas1.pack(fill = "both", expand = True)
# Display image
canvas1.create_image( 0, 0, image = bg,
anchor = "nw")
canvas1.create_text(250,250, text="SycoSpamBot")
L1 = Label(canvas1, text="Word")
L1.pack( side = LEFT)
E1 = Entry(canvas1)
E1.pack(side = RIGHT)
canvas1.create_window(100, 100, window=L1)
L2 = Label(canvas1, text="Amount")
L2.pack( side = LEFT)
E2 = Entry(canvas1)
E2.pack(side = RIGHT)
canvas1.create_window(100, 150, window=L2)
def Spammer ():
time.sleep(5)
x = 0
amount = int(E2.get())
word = E1.get()
while (amount > x):
pyautogui.typewrite(word)
pyautogui.press("enter")
x=x+1
button1 = Button(root, text = "Start", command=Spammer, bg="green")
button1_canvas = canvas1.create_window( 100, 10,
anchor = "nw",
window = button1)
root.mainloop()
Im wondering if I could make it so that the start button is at the bottom, and the word and amount labels are on the left side of a text input box.
This is how my GUI layout currently looks like. (Very Messy)
[1]: https://i.stack.imgur.com/UYvtU.png

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()

Tkinter Label: Retain Height when I change font to smaller size

I have an Label for a quite advanced calculator app.
I'd like to be able to change the font size when the text entered gets too long, to be able to enter more, but retain the height of the widget just for good looks.
Here's piece of code I tried:
self.biglabelfont = font.Font(family = "Arial", size = 24, weight = "bold")
self.entrylabel = Label(... font = self.biglabelfont ....)
self.entrylabel.pack(side = LEFT, fill = "x", expand = True)
self.entrylabel.propagate(0)
self.biglabelfont = font.Font(family = "Arial", size = 11, weight = "bold")
self.entrylabel.config(font = self.biglabelfont)
But it keeps shrinking the height.
Your choice to use pack_propagate is good, but you're doing it wrong. You must call it on the parent of the label widget, not on the label widget.
Here's a working example. Notice that the height of the sunken area doesn't change as the font grows and shrinks.
import Tkinter as tk
import tkFont
BG = "white"
HEIGHT = 75
def main():
global the_font, root
root = tk.Tk()
the_font = tkFont.Font(family="helvetica", size=18)
toolbar = make_toolbar(root)
subframe = make_subframe(root)
toolbar.pack(side="top", fill="x")
subframe.pack(side="top", fill="x")
root.geometry("400x400")
root.mainloop()
def make_subframe(parent):
frame = tk.Frame(parent, height=HEIGHT, borderwidth=1, relief="sunken", background=BG)
frame.pack_propagate(False)
label = tk.Label(frame, font=the_font, text="0123455.67890", background=BG)
label.pack(side="top", fill="both", expand=True)
return frame
def font_plus():
size = the_font.cget("size")
size += 2
the_font.configure(size=size)
def font_minus():
size = the_font.cget("size")
size -= 2
the_font.configure(size=size)
def make_toolbar(parent):
toolbar = tk.Frame(root)
grow = tk.Button(toolbar, text="Bigger", command=font_plus)
shrink = tk.Button(toolbar, text="Smaller", command=font_minus)
grow.pack(side="left")
shrink.pack(side="left")
return toolbar
main()

Resources