I've got a scrollbar inside my tkinter interface. It used to work no problem when it was inside of the main tkinter window. I've recently made some changes and placed the scrollable frame inside of a Toplevel() pop-up window. I've adjusted all of the related attributes so that the Toplevel() window is the new master, this is (self.pop_up), but I can no longer move the scrollbar?
Here's the code relevant to the scrollbar:
# create a container canvas then place a scrollbar and frame on top
container = ttk.Frame(self.pop_up)
canvas = tk.Canvas(master=container, height=self.pop_up_height, width=self.pop_up_width)
scrollbar = ttk.Scrollbar(container, orient="vertical", command=canvas.yview)
scrollable_frame = ttk.Frame(canvas, height=self.pop_up_height, width=self.pop_up_width)
# bind the scroll function
scrollable_frame.bind("<Configure>", lambda e: canvas.configure(scrollregion=canvas.bbox("all")))
# define the window position
canvas.create_window((10, 0), window=scrollable_frame, anchor="n")
# link the canvas to the scrollbar
canvas.configure(yscrollcommand=scrollbar.set)
Here's what the pop-up looks like:
And here's the full class which will create the window (the relevant code is in the generate_labels method:
class UnicodeWindow:
""" class for creating the unicode pop-up window """
def __init__(self):
# create the pop-up
self.pop_up = tk.Toplevel()
self.pop_up.wm_title('')
# define the pop up dimensions
self.pop_up_width = g.screen_width // 3
self.pop_up_height = g.screen_height // 2
# create the pop-up font
self.window_font = font.Font(size=26, family='Courier New')
# resize the window and make it central
self.pop_up.geometry(
f"{self.pop_up_width}x{self.pop_up_height}+{g.screen_width // 3}+{g.screen_height // 4}")
# add the select block message
self.message = tk.Label(self.pop_up, text='\n\nSelect a Block\n', font=self.window_font)
self.message.pack()
# add the block buttons
self.basic_latin_button = tk.Button(self.pop_up, text='Basic Latin', command=self.basic_latin, font=self.window_font,
width=20, pady=10)
self.basic_latin_button.pack()
self.l_supplement_button = tk.Button(self.pop_up, text='Latin Supplement', command=self.l_supplement, font=self.window_font,
width=20, pady=10)
self.l_supplement_button.pack()
self.latin_a_button = tk.Button(self.pop_up, text='Latin Extended-A', command=self.latin_a, font=self.window_font,
width=20, pady=10)
self.latin_a_button.pack()
self.latin_b_button = tk.Button(self.pop_up, text='Latin Extended-B', command=self.latin_b, font=self.window_font,
width=20, pady=10)
self.latin_b_button.pack()
self.exit_button = tk.Button(self.pop_up, text='Return', command=self.exit, font=self.window_font, width=20,
pady=10)
self.exit_button.pack()
# load the unicode dataframe
self.df = pd.read_csv('../unicode/unicode_db.csv')
def basic_latin(self):
self.block = 'Basic Latin'
self.generate_labels()
def l_supplement(self):
self.block = 'Latin-1 Supplement'
self.generate_labels()
def latin_a(self):
self.block = 'Latin Extended-A'
self.generate_labels()
def latin_b(self):
self.block = 'Latin Extended-B'
self.generate_labels()
def generate_labels(self):
""" function for displaying the unicode based on what block has been selected """
# destroy the original pop-up
self.pop_up.destroy()
# change the window geometry
self.pop_up_width = g.screen_width // 2
# create new pop-up
self.pop_up = tk.Toplevel()
self.pop_up.wm_title('')
# create the symbol font
symbol_font = font.Font(size=34, family='Courier New')
unicode_font = font.Font(size=10, family='Courier New')
# define the offset distance between symbols and their unicode
offset = 1.7
# resize the window and make it central
self.pop_up.geometry(
f"{self.pop_up_width}x{self.pop_up_height}+{g.screen_width // 4}+{g.screen_height // 4}")
# create a container canvas then place a scrollbar and frame on top
container = ttk.Frame(self.pop_up)
canvas = tk.Canvas(master=container, height=self.pop_up_height, width=self.pop_up_width)
scrollbar = ttk.Scrollbar(container, orient="vertical", command=canvas.yview)
scrollable_frame = ttk.Frame(canvas, height=self.pop_up_height, width=self.pop_up_width)
# bind the scroll function
scrollable_frame.bind("<Configure>", lambda e: canvas.configure(scrollregion=canvas.bbox("all")))
# define the window position
canvas.create_window((10, 0), window=scrollable_frame, anchor="n")
# link the canvas to the scrollbar
canvas.configure(yscrollcommand=scrollbar.set)
# get sub dataframe of relevant unicode
sub_df = self.df[self.df.block == self.block]
# iterate through unicode 8 at a time, creating the labels
count = 0
while len(sub_df) > 0:
if len(sub_df) >= 8:
next_uni = sub_df[:8]
else:
next_uni = sub_df
for index, row in next_uni.iterrows():
unicode = row['unicode']
symbol = chr(int(unicode, 16))
symbol_label = ttk.Label(master=scrollable_frame, text=symbol, font=symbol_font)
symbol_label.place(x=((index % 8 + 1) * (self.pop_up_width / 10)),
y=(count + 1) * (self.pop_up_height // 8))
unicode_label = ttk.Label(master=scrollable_frame, text=unicode, font=unicode_font)
unicode_label.place(x=((index % 8 + 1) * (self.pop_up_width / 10)),
y=(count + offset) * (self.pop_up_height // 8))
if len(sub_df) < 8:
break
# drop rows already visited
sub_df = sub_df[8:]
count += 1
canvas.pack()
container.pack()
scrollbar.place(x=self.pop_up_width*0.98, y=10)
#scrollbar.pack(side="right", fill="y")
# add the return button
rturn_button = tk.Button(self.pop_up, command=self.rturn, text='Return', width=20, font=self.window_font, pady=10)
rturn_button.place(x=self.pop_up_width/2, y=self.pop_up_height*0.85)
rturn_button.update()
rturn_width = rturn_button.winfo_width()
rturn_button.place(x=(self.pop_up_width/2 - rturn_width/2) , y=self.pop_up_height * 0.85)
def exit(self):
""" function for exiting the pop-up window """
self.pop_up.destroy()
def rturn(self):
""" function for returning to the parent unicode menu """
self.pop_up.destroy()
self.__init__()
So it turns out that this error occurs as a result of using place() to position my labels within scrollable_frame. As a result of this, scrollregion wasn't updating, which meant that there wasn't anywhere for the scrollbar to take me. The fix was to use grid() to position the scrollable_frame labels instead:
i = 0
for index, row in next_uni.iterrows():
unicode = row['unicode']
symbol = chr(int(unicode, 16))
symbol_label = ttk.Label(master=scrollable_frame, text=symbol, font=symbol_font)
unicode_label = ttk.Label(master=scrollable_frame, text=unicode, font=unicode_font)
symbol_label.grid(row=(2 * count), column=i, ipadx=self.pop_up_width//20)
unicode_label.grid(row=(2 * count + 1), column=i, ipadx=self.pop_up_width//20)
i += 1
Related
I have a tkInter window with a grid in it where each sell is containing several widgets. I want to make the window scalable and make grid cells scale accordingly:
import tkinter as tk
import math
def generate_pod(index, row, col, pod_list):
index = index
# Creating a pod and adding to the grid
pod_frame = tk.Frame(grid_window, borderwidth=0.5, relief="solid")
pod_frame.grid(row=row + 1, column=col)
# Create photoimage
img = tk.PhotoImage(width=160, height=90)
# Create a label diff image
img_label = tk.Label(pod_frame, image=img)
img_label.image = img # Keep a reference to prevent garbage collection
table_button = tk.Label(pod_frame, text=str(index))
score_frame = tk.Frame(pod_frame)
# Create a labels
ssim_label = tk.Label(score_frame, text='Sim: ')
# Movement
move_label = tk.Label(score_frame, text='Movement')
# Brightness
bright_label = tk.Label(score_frame, text='Brigh: ')
# Focus
sharp_label = tk.Label(score_frame, text='Foc: ')
alert_pod = tk.Label(alert_window, text=str(index))
# Add the labels to the pod
img_label.pack(side='top')
score_frame.pack(side='bottom')
table_button.pack(side='bottom')
ssim_label.grid(row=1, column=1)
move_label.grid(row=1, column=2)
bright_label.grid(row=2, column=1)
sharp_label.grid(row=2, column=2)
alert_pod.pack(side='top')
def refresh_pods(grid_rows, grid_cols):
# Destroy any existing widgets in the grid_window
for widget in grid_window.winfo_children():
widget.destroy()
pod_list = []
# Create a grid
for row in range(grid_rows):
for col in range(grid_cols):
# Calculate the index of the current pod
index = row * grid_cols + col
grid_window.rowconfigure(row, weight=1)
grid_window.columnconfigure(col, weight=1)
try:
generate_pod(index, row, col, pod_list)
except Exception as e:
print(e)
# Composing header
header_text = 'Header'
header = tk.Label(grid_window, text=header_text)
header.grid(row=0, column=0, columnspan=grid_cols)
# Schedule the refresh_pods() function to be called again in 2 min
main_window.after(120000, lambda: refresh_pods(grid_rows, grid_cols))
# Getting count of tables and count grid size
table_count = 50
grid_cols = math.floor(math.sqrt(table_count) * 1.2)
grid_rows = math.ceil(table_count/grid_cols)
grid_cols = int(grid_cols)
grid_rows = int(grid_rows)
# Create the main window
main_window = tk.Tk()
main_window.title('CDN snapshots aplha ver')
main_window.eval('tk::PlaceWindow . center')
main_window.resizable(True, True)
# Create a frame for the pods
grid_window = tk.Frame(main_window)
grid_window.pack(side='left', anchor='nw')
alert_window = tk.Frame(main_window)
alert_window.pack(side='right')
# Show the first page of pods
refresh_pods(grid_rows, grid_cols)
# Run the main loop
main_window.mainloop()
I found this snippet in the web that is working as I intend, but I failed to apply it to my code, mostly because all pod generation happens in functions and I didn't manage to pass arguments to labels and vice versa label list out of function
import tkinter as tk
import tkinter.font as tkFont
root = tk.Tk()
label_list = []
font = tkFont.Font(family="Helvetica")
pixel = tk.PhotoImage(width=100, height=1)
for x in range(3):
for y in range(3):
root.rowconfigure(y, weight=1)
root.columnconfigure(x, weight=1)
label_list.append(tk.Label(root, width=40, height=40, image=pixel, relief="groove", compound="center"))
label_list[-1].grid(row=x, column=y, sticky="nsew")
def font_resize(event=None):
for lbl in label_list:
x = lbl.winfo_width()
y = lbl.winfo_height()
root.bind( "<Configure>", font_resize)
root.mainloop()
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()
Current behavior, adding LabelFrame widgets (with their own label and picture children) into another Labelframe named "Test putting buffs..." The LabelFrame widgets are being added into the left side of the LabelFrame and "grow" to the right. Wanted behavior is for the widgets to appear on the right side of the frame and "grow" left.
Cannot seem to get there with anchor or sticky settings. How can this "grow-left" be done and still preserve the ability to sort by name or time remaining?
Current behavior gif:
Wanted behavior (mocked up with paint):
Code (took out the image stuff so files aren't needed to run):
import tkinter as tk
from tkinter import ttk
from PIL import ImageTk, Image
import time
class MainFrame(tk.Frame):
def __init__(self, container):
super().__init__(container)
self.grid(column=0, row=0)
self.buffs_list_frames = []
self.button1 = ttk.Button(self)
self.button1['text'] = "Simulate frame list appended True Strike"
self.button1['command'] = lambda: self.buffs_frame_list_is_appended(["True Strike", time.time() + 9])
self.button1.grid(column=0, row=0)
self.button2 = ttk.Button(self)
self.button2['text'] = "Simulate frame list appended Bulls"
self.button2['command'] = lambda: self.buffs_frame_list_is_appended(["Bulls", time.time() + 1080])
self.button2.grid(column=0, row=1)
self.button0 = ttk.Button(self)
self.button0['text'] = "Simulate frame list appended Endurance"
self.button0['command'] = lambda: self.buffs_frame_list_is_appended(["Endurance", time.time() + 1080])
self.button0.grid(column=0, row=2)
self.button3 = ttk.Button(self)
self.button3['text'] = "Simulate frame list put into .grid() and displayed"
self.button3['command'] = lambda: self.buffs_display_nicely()
self.button3.grid(column=0, row=3)
self.button4 = ttk.Button(self)
self.button4['text'] = "START loops of time passing"
self.button4['command'] = lambda: self.buffs_loop_time_passing()
self.button4.grid(column=0, row=4)
self.test_label_frame = ttk.LabelFrame(self, text="Testing putting buffs into a frame with grid")
self.test_label_frame.grid(column=1, row=0)
def buffs_loop_time_passing(self):
for x in self.buffs_list_frames:
x.buff_timer.set(f"{x.buff_birthday - time.time():.1f}s")
if x.buff_birthday < time.time() + 6:
x['background'] = 'red'
if x.buff_birthday < time.time():
self.buffs_list_frames.remove(x)
x.destroy()
self.after(1000, self.buffs_loop_time_passing)
def buffs_frame_list_is_appended(self, added_buff):
""" makes the buff frame and adds to the list of frame widgets
"""
self.buff_frame = tk.LabelFrame(self.test_label_frame, borderwidth=1, text=added_buff[0][0:4], labelanchor="n")
# self.buff_frame.buff_image_reference = ImageTk.PhotoImage(Image.open(added_buff[2]))
# self.buff_frame.buff_image_label = ttk.Label(self.buff_frame, image=self.buff_frame.buff_image_reference)
# self.buff_frame.buff_image_label.image_keep = self.buff_frame.buff_image_reference
# self.buff_frame.buff_image_label.grid(column=0, row=0)
self.buff_frame.buff_birthday = added_buff[1]
self.buff_frame.buff_timer = tk.StringVar()
self.buff_frame.buff_timer.set(f"{self.buff_frame.buff_birthday - time.time():.1f}s")
self.buff_frame.buff_label = ttk.Label(self.buff_frame, textvariable=self.buff_frame.buff_timer)
self.buff_frame.buff_label.grid(column=0, row=1)
self.buffs_list_frames.append(self.buff_frame)
self.buffs_display_nicely()
def buffs_display_nicely(self):
""" takes the list of frames, sorts by name, and .grids()s them into the test frame
"""
self.buffs_list_frames = sorted(self.buffs_list_frames, key=lambda z: z['text'])
print(f"sorted? {self.buffs_list_frames}")
j = 0
for x in self.buffs_list_frames:
x.grid(row=0, column=j)
j += 1
class App(tk.Tk):
def __init__(self):
super().__init__()
# configure the root window
self.title('NWN Buff Watcher')
self.geometry('300x50')
if __name__ == "__main__":
app = App()
main_frame = MainFrame(app)
app.mainloop()
Try this (using #acw1668's suggestion):
import tkinter as tk
from tkinter import ttk
from PIL import ImageTk, Image
import time
class MainFrame(tk.Frame):
def __init__(self, container):
super().__init__(container)
self.buffs_list_frames = []
self.buttons_frame = tk.Frame(self)
self.buttons_frame.pack(fill="both", side="left")
self.button1 = ttk.Button(self.buttons_frame, text="Simulate frame list appended True Strike",
command=lambda: self.buffs_frame_list_is_appended("True Strike", 9))
self.button1.grid(column=0, row=0)
self.button2 = ttk.Button(self.buttons_frame, text="Simulate frame list appended Bulls",
command=lambda: self.buffs_frame_list_is_appended("Bulls", 1080))
self.button2.grid(column=0, row=1)
self.button0 = ttk.Button(self.buttons_frame, text="Simulate frame list appended Endurance",
command=lambda: self.buffs_frame_list_is_appended("Endurance", 1080))
self.button0.grid(column=0, row=2)
#self.button3 = ttk.Button(self.buttons_frame, text="Order items", command=self.order_items)
#self.button3.grid(column=0, row=3)
self.button4 = ttk.Button(self.buttons_frame, text="START loops of time passing",
command=self.buffs_loop_time_passing)
self.button4.grid(column=0, row=4)
self.test_label_frame = ttk.LabelFrame(self, text="Testing putting buffs into a frame with grid")
self.test_label_frame.pack(side="right")
def buffs_loop_time_passing(self):
for x in self.buffs_list_frames:
x.buff_timer.set(f"{x.buff_birthday - time.time():.1f}s")
time_now = time.time()
if x.buff_birthday < time_now + 6:
x.config(bg="red")
if x.buff_birthday < time_now:
self.buffs_list_frames.remove(x)
x.destroy()
self.after(100, self.buffs_loop_time_passing)
def buffs_frame_list_is_appended(self, added_buff, time_alive):
""" makes the buff frame and adds to the list of frame widgets
"""
buff_frame = tk.LabelFrame(self.test_label_frame, borderwidth=1,
text=added_buff[:4], labelanchor="n")
# buff_frame.buff_image_reference = ImageTk.PhotoImage(Image.open(added_buff[2]), master=self)
# buff_frame.buff_image_label = ttk.Label(buff_frame, image=buff_frame.buff_image_reference)
# buff_frame.buff_image_label.image_keep = buff_frame.buff_image_reference
# buff_frame.buff_image_label.grid(column=0, row=0)
buff_frame.buff_birthday = time.time() + time_alive
buff_frame.buff_timer = tk.StringVar(master=self)
buff_frame.buff_timer.set(f"{buff_frame.buff_birthday - time.time():.1f}s")
buff_frame.buff_label = ttk.Label(buff_frame,
textvariable=buff_frame.buff_timer)
buff_frame.buff_label.grid(column=0, row=1)
self.buffs_list_frames.append(buff_frame)
self.order_items()
def order_items(self):
self.buffs_list_frames = sorted(self.buffs_list_frames, key=lambda z: z['text'], reverse=True)
for x in self.buffs_list_frames:
x.pack_forget()
x.pack(side="right")
class App(tk.Tk):
def __init__(self):
super().__init__()
# configure the root window
self.title("NWN Buff Watcher")
# self.geometry("300x50")
if __name__ == "__main__":
app = App()
main_frame = MainFrame(app)
main_frame.pack()
app.mainloop()
I made a few changes to your code. The main thing is that I removed buffs_display_nicely and instead added buff_frame.pack(side="right"). The side="right" tells tkinter to add the widgets from the right to the left.
Also you can improve your code by a lot if you add a class instead of using buff_frame.buff_birthday, buff_frame.buff_timer, ... Also it will make your life a lot easier
from tkinter import *
from random import *
class Game:
def __init__(self):
self.root = Tk()
self.frame1 = Frame(self.root, width = 1055, height = 30)
self.frame1.pack()
self.frame_lvl = Frame(self.root, width = 1055, height = 1055)
self.frame_lvl.pack()
for frame_lvl in range(0,31):
self.frame_lvl = Frame(self.root)
self.frame_lvl.pack(side = BOTTOM)
for i in range(0,31):
for j in range(0,31):
button = Button(self.i, width = 30, height = 30, padx = 2, pady = 2)
button.pack(side = LEFT)
self.root.mainloop()
app = Game()
So I try to create a new frame level so the buttons won't keep printing on the same line but I'm not sure if the frame level will be saved as self.0, self.1, self.2, etc...
When I tried making the frame a grid and adjusting the width, height, rowspan, and column span, I got the error ("cannot use geometry manager grid inside . which already has slaves managed by pack") The error comes from these lines:
self.frame2 = Frame(width = 1055, height = 1055)
self.frame2.grid(columnspan = 30, rowspan = 30)
Any suggestions.
Note that there is only one self.frame_lvl so each time you assign it a new value you lose the existing value. In the end it will only contain the last value assigned to it. Also
for i in range(31):
for j in range(31):
creates 31*31 buttons(which is over 900 buttons). While you are learning, stick with all grid() or all pack() in a program until you learn how to mix the two. To create 3 rows of 5 buttons using grid()
from tkinter import *
from functools import partial
class Game:
def __init__(self):
self.root = Tk()
self.frame1 = Frame(self.root, width = 900, height = 30)
self.frame1.grid()
self.label=Label(self.frame1, text="")
self.label.grid(row=0, column=0, columnspan=5)
## save each button id in a list
self.list_of_button_ids=[]
for ctr in range(15):
## use partial to pass the button number to the
## function each time the button is pressed
button = Button(self.frame1, text=str(ctr), width = 20,
height = 20, padx = 2, pady = 2,
command=partial(self.button_callback, ctr))
this_row, this_col=divmod(ctr, 5)
## the label is in the top row so add one to each row
button.grid(row=this_row+1, column=this_col)
## add button's id to list
self.list_of_button_ids.append(button)
self.root.mainloop()
def button_callback(self, button_num):
""" display button number pressed in the label
"""
self.label.config(text="Button number %s and it's id=%s"
% (button_num, self.list_of_button_ids[button_num]))
app = Game()
HI i am trying to place the alignment of my Entry(Text Box) according to the image below. I tried everything, TOP BOTTOM LEFT RIGHT.
This is the alignment i want. Obtained from paint program*
Problem
Coding of tkinter
master = Tk.Tk() # Open up GUI connection
master.title('Program Application')
print "VSM activated input range first (X2 must be larger than X1)"
#Declare button and respective method
button = Tk.Button(text='VSM', command=VSM, fg="red")
button.config( height = 10, width = 80 )
button.pack() #pack is needed to display the button
bluebutton = Tk.Button(text="AGM Folder",command= lambda: Folder(0), fg="blue").pack(side = LEFT)
bluebutton = Tk.Button(text="VSM Folder",command= lambda: Folder(1), fg="blue").pack(side = RIGHT)
Label(text='Correct Range for Gradient\nX2 X1').pack(side=TOP,padx=10,pady=10)
entryX2 = Entry(master, width=10)
entryX2.pack(side=LEFT,padx=10,pady=10)
entryX1 = Entry(master,width=10)
entryX1.pack(side=RIGHT,padx=10,pady=10)
buttonGradient = Tk.Button(text='Input Range OP',command= lambda: Folder(2), fg="red").pack()
entryX2IP = Entry(master, width=10)
entryX2IP.pack(side=LEFT,padx=10,pady=10)
entryX1IP = Entry(master,width=10)
entryX1IP.pack(side=RIGHT,padx=10,pady=10)
btnGradientIP = Tk.Button(text='Input Range IP',command= lambda: Folder(2), fg="red").pack(side = TOP)
master.mainloop() # Continue loop till user close tab
Use Frame:
master = Tk.Tk() # Open up GUI connection
master.title('Program Application')
print "VSM activated input range first (X2 must be larger than X1)"
#Declare button and respective method
button = Tk.Button(text='VSM', command=VSM, fg="red")
button.config( height = 10, width = 80 )
button.pack() #pack is needed to display the button
bluebutton = Tk.Button(text="AGM Folder",command= lambda: Folder(0), fg="blue").pack(side = LEFT)
bluebutton = Tk.Button(text="VSM Folder",command= lambda: Folder(1), fg="blue").pack(side = RIGHT)
Label(text='Correct Range for Gradient\nX2 X1').pack(side=TOP,padx=10,pady=10)
################### Use 3 frames to contains entries, buttons.
frameX2 = Frame(master)
frameX2.pack(side=LEFT, expand=1, anchor=E)
entryX2 = Entry(frameX2, width=10)
entryX2.pack(side=TOP,padx=10,pady=10)
entryX2IP = Entry(frameX2, width=10)
entryX2IP.pack(side=TOP,padx=10,pady=10)
frameButton = Frame(master)
frameButton.pack(side=LEFT)
Tk.Button(frameButton, text='Input Range OP',command= lambda: Folder(2), fg="red").pack(padx=10, pady=10)
Tk.Button(frameButton, text='Input Range IP',command= lambda: Folder(2), fg="red").pack(padx=10, pady=10)
frameX1 = Frame(master)
frameX1.pack(side=LEFT, expand=1, anchor=W)
entryX1 = Entry(frameX1,width=10)
entryX1.pack(side=TOP,padx=10,pady=10)
entryX1IP = Entry(frameX1,width=10)
entryX1IP.pack(side=TOP,padx=10,pady=10)
#####################
master.mainloop() # Continue loop till user close tab