Python Forum
Centering and adding a push button to a grid window, TKinter
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Centering and adding a push button to a grid window, TKinter
#1
This May be really simple, but I'm not finding enough details to help as I'm just learning TKinter.

I have a simple grid sourced by a Python list, and I'm trying to center it regardless of window size, and add single push button at bottom of the window.
What I have tested caused the full window to grey out.

my code:
import tkinter as tk
from tkinter import *
import tkinter.font as font
window = tk.Tk()
window.title("Feed Bins")
window.geometry("800x400")

aList = ["Bin 1", "Bin 2", "Bin 3", "Bin 4", "Bin 5","Bin 6", "Bin 7", "Bin 8", "Bin 9", "Bin 10", "Bin 11",
        "Bin 12", "Bin 13", "Bin 14", "Bin 15"]
onList = ["Bin 3", "Bin 12", "Bin 14"] # For testing, usually empty

myFont2 = font.Font(size=10)

label= [0] * 15
for x in range(5):    # Number of Rows
   for y in range(3): #Number of Colums
       frame = tk.Frame(master=window,relief=tk.RAISED,borderwidth=4)
       frame.grid(row=x, column=y, padx=5, pady=5)  # line 13
       label[x+(y*5)] = tk.Label(master=frame, text=aList[x+(y*5)],font=myFont2, height=3, width=20)
       label[x+(y*5)].pack(fill="x")

def check_alerts():
   global aList,onList
   for x in range(0,len(aList)):
       if aList[x] in onList:
           label[x].config(bg = "red")
       else:
           label[x].config(bg = "lightgrey")
   window.after(1000,check_alerts)
   
check_alerts()

window.mainloop()   
[Image: gridOnly.png]

Any assistance greatly appreciated.
Reply
#2
To center justify a label you set "justify = tk.CENTER". The label will have to be the same width as the buttons, so you should set sticky=
"NEWS".
Reply
#3
Your code altered a little. Expands with the window

import tkinter as tk

aList = ["Bin 1", "Bin 2", "Bin 3", "Bin 4", "Bin 5","Bin 6", "Bin 7", "Bin 8", "Bin 9", "Bin 10", "Bin 11",
        "Bin 12", "Bin 13", "Bin 14", "Bin 15"]

root = tk.Tk()
root['padx'] = 5
root['pady'] = 5
root.title('Feed Bins')

root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)

frame = tk.Frame(root)
frame['highlightbackground'] = 'black'
frame['highlightcolor'] = 'black'
frame['highlightthickness'] = 1
frame.grid(column=0, row=0, sticky='news', padx=5, pady=5)

for x in range(5):
    frame.grid_rowconfigure(x, weight=3, uniform='rows')
    for y in range(3):
        frame.grid_columnconfigure(y, weight=3, uniform='cols')
        label = tk.Label(frame, text=aList[x+(y*5)], relief='raised', font=(None, 16, 'bold'))
        label['bg'] = 'red' if aList[x+(y*5)] in ['Bin 3', 'Bin 12', 'Bin 14'] else 'gray86'
        label.grid(column=y, row=x, sticky='news', padx=5, pady=5)


btn = tk.Button(root, text='Button', font=(None, 14, 'bold'))
btn.grid(column=0, row=1)

root.mainloop()
I welcome all feedback.
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags


Reply
#4
Sorry, I answered the wrong question again.

To place a frame in the middle of the window, use "frame.place(relx=0.5, rely=0.5, anchor=tk.CENTER)".
import tkinter as tk
import random


class FramedLabel(tk.Frame):
    """A label with a frame.  Looks suspiciously like a button."""
    def __init__(
            self,
            parent,
            text="",
            relief=tk.RAISED,
            borderwidth=4,
            font=(None, 10),
            width=10,
            height=3,
            **kwargs):
        super().__init__(
            parent, relief=relief, borderwidth=borderwidth, **kwargs
        )
        self.label = tk.Label(
            self, text=text, font=font, width=width, height=height
        )
        self.label.pack()

    def set_color(self, color):
        self["bg"] = color
        self.label["bg"] = color


class MyWindow(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Feed Bins")
        self.geometry("800x400")

        frame = tk.Frame(self)
        frame.place(relx=0.5, rely=0.5, anchor=tk.CENTER)
        self.labels = [
            FramedLabel(frame, text=f"Bin {x}") for x in range(1, 16)
        ]
        for x, label in enumerate(self.labels):
            label.grid(row=x // 5, column=x % 5, padx=5, pady=5)
            label.set_color("lightgrey")

        button = tk.Button(frame, text="Update", command=self.check_alerts)
        button.grid(row=4, column=0, columnspan=5, sticky="news")

    def check_alerts(self):
        for label in self.labels:
            label.set_color(random.choice(("red", "lightgrey")))

 
MyWindow().mainloop() 
However, I prefer to pack the frame and set the borders to expand the window to the desired size.
import tkinter as tk
import random


class FramedLabel(tk.Frame):
    """A label with a frame.  Looks suspiciously like a button."""
    def __init__(
            self,
            parent,
            text="",
            relief=tk.RAISED,
            borderwidth=4,
            font=(None, 10),
            width=10,
            height=3,
            **kwargs):
        super().__init__(
            parent, relief=relief, borderwidth=borderwidth, **kwargs
        )
        self.label = tk.Label(
            self, text=text, font=font, width=width, height=height
        )
        self.label.pack()

    def set_color(self, color):
        self["bg"] = color
        self.label["bg"] = color


class MyWindow(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Feed Bins")

        frame = tk.Frame(self)
        frame.pack(padx=100, pady=100)
        self.labels = [
            FramedLabel(frame, text=f"Bin {x}") for x in range(1, 16)
        ]
        for x, label in enumerate(self.labels):
            label.grid(row=x // 5, column=x % 5, padx=5, pady=5)
            label.set_color("lightgrey")

        button = tk.Button(frame, text="Update", command=self.check_alerts)
        button.grid(row=4, column=0, columnspan=5, sticky="news")

    def check_alerts(self):
        for label in self.labels:
            label.set_color(random.choice(("red", "lightgrey")))

 
MyWindow().mainloop() 
Either way, the real trick is to create a frame that holds your labels and buttons. Pack (or grid) the labels and buttons in the frame. Place or pack the frame in the window
Reply
#5
Thanks to all, you all are a part of my TKinter crash-course.

Menator01,
In 'Your code altered a little' code, the onList[] in this project will be getting additions and removals every few minutes possibly, so I made this minor change:
label['bg'] = 'red' if aList[x+(y*5)] in onList else 'gray86' 
and re-added the checkAlerts() function.

Looks like my checkAlerts() function is necessary to update the label colors when the onList[] values come and go.

Any thoughts why the checkAlerts() function below might cause this error within TKInter?
File "/usr/lib/python3.9/tkinter/__init__.py", line 1652, in cget
return self.tk.call(self._w, 'cget', '-' + key)
TypeError: can only concatenate str (not "int") to str


Doesn't throw this error in my original code.
Reply
#6
Post the full error trace and the code that raises the error.

There is no reason to use global in this function
def check_alerts():
   global aList,onList   # Only affects assignment.  Function does not assign values to aList or onList
   for x in range(0,len(aList)):
       if aList[x] in onList:
           label[x].config(bg = "red")
       else:
           label[x].config(bg = "lightgrey")
   window.after(1000,check_alerts)
Reply
#7
(May-21-2023, 01:56 AM)deanhystad Wrote: To center justify a label you set "justify = tk.CENTER". The label will have to be the same width as the buttons, so you should set sticky=
"NEWS".
using:
frame = tk.Frame(master=window,relief=tk.RAISED,justify=tk.CENTER,borderwidth=4)
Gives:
self.tk.call(
_tkinter.TclError: unknown option "-justify"
Reply
#8
From my quote (that you included in your last post).
Quote:To center justify a label you set "justify = tk.CENTER".
"justify" works with labels, but later I realized you weren't asking how to center a label and I wrote this post:

https://python-forum.io/thread-40023-pos...#pid169617

Which shows how you can center a frame using the place() command.
Reply
#9
I have one more example. Doesn't use the button to update. uses after. Sometimes pulls the same bin multiple times in the comparison list though.
So instead of three red labels, will get only one or two.

import tkinter as tk
from random import choices

aList = ["Bin 1", "Bin 2", "Bin 3", "Bin 4", "Bin 5","Bin 6", "Bin 7", "Bin 8", "Bin 9", "Bin 10", "Bin 11",
        "Bin 12", "Bin 13", "Bin 14", "Bin 15"]


def checker(root, labels):
    bins = choices(aList, k=3)
    print(bins)
    for label in labels:
        label['bg'] = 'red' if label['text'] in bins else 'gray86'
    root.after(1000, lambda: checker(root, labels))


root = tk.Tk()
root['padx'] = 5
root['pady'] = 5
root.title('Feed Bins')

root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)

frame = tk.Frame(root)
frame['highlightbackground'] = 'black'
frame['highlightcolor'] = 'black'
frame['highlightthickness'] = 1
frame.grid(column=0, row=0, sticky='news', padx=5, pady=5)

_labels = []
i = 0
for x in range(5):
    frame.grid_rowconfigure(x, weight=3, uniform='rows')
    for y in range(3):
        frame.grid_columnconfigure(y, weight=3, uniform='cols')
        _labels.append(tk.Label(frame, text=aList[x+(y*5)], relief='raised', font=(None, 16, 'bold')))
        _labels[i]['bg'] = 'gray86'
        _labels[i].grid(column=y, row=x, sticky='news', padx=5, pady=5)
        i+=1


btn = tk.Button(root, text='Button', font=(None, 14, 'bold'))
btn.grid(column=0, row=1, pady=8)
root.after(1000, lambda: checker(root, _labels))
root.mainloop()
I welcome all feedback.
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags


Reply
#10
So I now have a strange error in the centering grid when I use the needed check_alerts() function from my original code.
Or should I make a separate post?

The error is:
File "/usr/lib/python3.9/tkinter/__init__.py", line 1652, in cget
    return self.tk.call(self._w, 'cget', '-' + key)
TypeError: can only concatenate str (not "int") to str 
The full code I'm testing is below. Not sure why the check_alerts() function causes this after centering changes.
import tkinter as tk
 
aList = ["Bin 1", "Bin 2", "Bin 3", "Bin 4", "Bin 5","Bin 6", "Bin 7", "Bin 8", "Bin 9", "Bin 10", "Bin 11",
        "Bin 12", "Bin 13", "Bin 14", "Bin 15"]
onList = ["Bin 3", "Bin 14"] #For test, usually empty
 
root = tk.Tk()
root['padx'] = 5
root['pady'] = 5
root.title('Feed Bins')
root.geometry("1200x900")
 
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
 
frame = tk.Frame(root)
frame['highlightbackground'] = 'black'
frame['highlightcolor'] = 'black'
frame['highlightthickness'] = 1
frame.grid(column=0, row=0, sticky='nsew', padx=5, pady=5)
 
for x in range(5):
    frame.grid_rowconfigure(x, weight=3, uniform='rows')
    for y in range(3):
        frame.grid_columnconfigure(y, weight=3, uniform='cols')
        label = tk.Label(frame, text=aList[x+(y*5)], relief='raised', font=(None, 16, 'bold'))
        label['bg'] = 'red' if aList[x+(y*5)] in onList else 'gray86'
        label.grid(column=y, row=x, sticky='nsew', padx=5, pady=5)
 
 #check_alerts()
btn = tk.Button(root, text='Add item to onList', font=(None, 14, 'bold'), command = lambda: [onList.append("Bin 9"), print("Button Press")])
btn.grid(column=0, row=1)
 
def check_alerts():
    global aList,onList
    for x in range(0,len(aList)):
       if aList[x] in onList:
           label[x].config(bg = "red")
       else:
           label[x].config(bg = "lightgrey")
           root.after(1000,check_alerts)
   
check_alerts() 
root.mainloop()
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Interaction between Matplotlib window, Python prompt and TKinter window NorbertMoussy 3 537 Mar-17-2024, 09:37 AM
Last Post: deanhystad
  [Tkinter] TKinter Remove Button Frame Nu2Python 8 1,025 Jan-16-2024, 06:44 PM
Last Post: rob101
  tkinter - touchscreen, push the button like click the mouse John64 5 875 Jan-06-2024, 03:45 PM
Last Post: deanhystad
  Tkinter multiple windows in the same window tomro91 1 866 Oct-30-2023, 02:59 PM
Last Post: Larz60+
  [Tkinter] Open tkinter colorchooser at toplevel (so I can select/focus on either window) tabreturn 4 1,925 Jul-06-2022, 01:03 PM
Last Post: deanhystad
  [Tkinter] Background inactivity timer when tkinter window is not active DBox 4 2,941 Apr-16-2022, 04:04 PM
Last Post: DBox
  [Tkinter] Clicking on the button crashes the TK window ODOshmockenberg 1 2,257 Mar-10-2022, 05:18 PM
Last Post: deanhystad
  why my list changes to a string as I move to another window in tkinter? pymn 4 2,584 Feb-17-2022, 07:02 AM
Last Post: pymn
  Can't get tkinter button to change color based on changes in data dford 4 3,447 Feb-13-2022, 01:57 PM
Last Post: dford
  [Tkinter] Tkinter Window Has no Title Bar gw1500se 4 2,872 Nov-07-2021, 05:14 PM
Last Post: gw1500se

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020