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()
Related
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()
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
I am running into an error with my MultiColumnListbox. I am trying to understand how to fix this issue. I am trying to see what is selected in my multicolumn listbox. The mutlicolumn listbox is built using tkinter and has a submit button which should run a function telling me what rows were selected in the multi column listbox. I am receiving this error 'MultiColumnListbox' object has no attribute 'curselection' and cant seem to fix it.
This is my code
import os
import time
import glob
import datetime
from array import *
try:
import Tkinter as tk
import tkFont
import ttk
except ImportError: # Python 3
import tkinter as tk
import tkinter.font as tkFont
import tkinter.ttk as ttk
class MultiColumnListbox(object):
"""use a ttk.TreeView as a multicolumn ListBox"""
def submitFunction():
selection = listbox.curselection()
for k in range(0,len(selection)):
selected = listbox.curselection()[k]
def __init__(self):
self.tree = None
self._setup_widgets()
self._build_tree()
def _setup_widgets(self):
s = """\click on header to sort by that column
to change width of column drag boundary
"""
msg = ttk.Label(wraplength="4i", justify="left", anchor="n",
padding=(10, 2, 10, 6), text=s)
msg.pack(fill='x')
container = ttk.Frame()
container.pack(fill='both', expand=True)
# create a treeview with dual scrollbars
self.tree = ttk.Treeview(columns=car_header, show="headings")
vsb = ttk.Scrollbar(orient="vertical",
command=self.tree.yview)
hsb = ttk.Scrollbar(orient="horizontal",
command=self.tree.xview)
self.tree.configure(yscrollcommand=vsb.set,
xscrollcommand=hsb.set)
self.tree.grid(column=0, row=0, sticky='nsew', in_=container)
vsb.grid(column=1, row=0, sticky='ns', in_=container)
hsb.grid(column=0, row=1, sticky='ew', in_=container)
container.grid_columnconfigure(0, weight=1)
container.grid_rowconfigure(0, weight=1)
def _build_tree(self):
for col in car_header:
self.tree.heading(col, text=col.title(),
command=lambda c=col: sortby(self.tree, c, 0))
# adjust the column's width to the header string
self.tree.column(col,
width=tkFont.Font().measure(col.title()))
for item in car_list:
self.tree.insert('', 'end', values=item)
# adjust column's width if necessary to fit each value
for ix, val in enumerate(item):
col_w = tkFont.Font().measure(val)
if self.tree.column(car_header[ix],width=None)<col_w:
self.tree.column(car_header[ix], width=col_w)
def sortby(tree, col, descending):
"""sort tree contents when a column header is clicked on"""
# grab values to sort
data = [(tree.set(child, col), child) \
for child in tree.get_children('')]
# if the data to be sorted is numeric change to float
#data = change_numeric(data)
# now sort the data in place
data.sort(reverse=descending)
for ix, item in enumerate(data):
tree.move(item[1], '', ix)
# switch the heading so it will sort in the opposite direction
tree.heading(col, command=lambda col=col: sortby(tree, col, \
int(not descending)))
FilesToDeleteName = [];
FilesToDeletePath = [];
FilesToDeleteDate = [];
car_list = [];
car_list.append([])
car_list.append([])
#str1 = input("Enter number of days old: ")
#days = int(str1)
days = 90
count = 0
time_in_secs = time.time() - (days * 24 * 60 * 60)
extf = ['Windows','Program Files', 'Program Files (x86)']
for (root, dirs, files) in os.walk('C:/Users', topdown=True):
dirs[:] = [d for d in dirs if d not in extf]
for filename in files:
Fullname = os.path.join(root,filename)
stat = os.stat(Fullname)
modified = datetime.datetime.fromtimestamp(stat.st_mtime)
if Fullname.endswith('.pcapng') or Fullname.endswith('.evtx') or Fullname.endswith('.png') or Fullname.endswith('.sql') or Fullname.endswith('.etl') or Fullname.endswith('.zip'):
if stat.st_mtime <= time_in_secs:
FilesToDeleteName.append(filename);
FilesToDeletePath.append(Fullname);
FilesToDeleteDate.append(str(modified));
FilesToDelete = [];
for p in range(0,len(FilesToDeletePath)):
STR2 = FilesToDeletePath[p],FilesToDeleteDate[p]
FilesToDelete.append(STR2)
car_list = FilesToDelete
car_header = ["Path ", "Date Modified"]
if __name__ == '__main__':
window = tk.Tk()
window.title("Multicolumn Treeview/Listbox")
listbox = MultiColumnListbox()
def submitFunction():
print(listbox.curselection(self))
window.destroy()
def closeFunction():
window.destroy()
submit = tk.Button(window, text='Submit', command=submitFunction)
submit.pack(side=tk.RIGHT, padx = 20)
close = tk.Button(window, text='Close', command=closeFunction)
close.pack(side=tk.RIGHT)
window.mainloop()
This is the main part of my issue
def submitFunction():
print(listbox.curselection(self))
window.destroy()
I will ultimately be trying to get the index numbers to delete the given file path
I am currently working on a program where I need to change the position of a widget.
Here is my code:
root = Tk()
frame = Frame(root, bg="black")
label1 = Label(frame, text="not important")
label.grid(row=1, column=1)
#some stuff happens
x = aFunctionThatReturnsXCoordinate #not actual name
y = aFunctionThatReturnsYCoordinate
Now I want to change the position of label1 to the new coordinates.
I have tried:
label1.forget_grid()
label1.grid(rows=x, columns=y)
#Ive tried label1/frame.update after this code but it didnt do anything
I've also tried to do it without the grid_forget.
I didn't forget the frame.pack and root.mainloop.
Is there a function to change the position?
I have made a code which contains a label and a button. When the button is pressed , the row of the label changes from 0 to 1 and when pressed again row is changes from 1 to 0 and so on. To make difference between the frame and the root, I have set the color of the frame to sky blue and that of root to pink.
from tkinter import *
global rw;rw = 0
def changed():
global rw;rw += 1;
if rw == 2:rw=0
label.grid(row=rw,column=0)
root = Tk()
root.config(bg="pink")
frame = Frame(root, bg="sky blue")
frame.pack()
label = Label(frame,text="Hello")
label.grid(row=0,column=0)
b = Button(frame, text='Press me!', command=changed)
b.grid(row=0, column=1)
root.mainloop()
Well, the above code is a bit complicated so , if you want a simpler way to do the same:
from tkinter import *
def changed():
size = label.grid_info().get("row") #getting current row
if size == 0:size = 1
elif size == 1:size = 0
label.grid(row=size,column=0)
root = Tk()
root.config(bg="pink")
frame = Frame(root, bg="sky blue")
frame.pack()
label = Label(frame,text="Hello")
label.grid(row=0,column=0)
b = Button(frame, text='Press me!', command=changed)
b.grid(row=0, column=1)
root.mainloop()
Here is an animation:
Here is an example that toggles the position of a label from column 0 to column 1:
You have to keep in mind that unoccupied rows or columns are sized at zero pixels by the grid geometry manager.
pressing the button makes the label in row 1 swap places from column 0 to 1 and vice versa.
import tkinter as tk
def move_label(ndx=[0]):
# the 3 next toggle the column value
rowcol = [(1, 1), (1, 0)]
x, y = rowcol[ndx[0]]
ndx[0] = (ndx[0] + 1) % 2
label_at_1_0.grid(row=x, column=y)
root = tk.Tk()
frame = tk.Frame(root, bg="black")
frame.pack()
label_at_0_0 = tk.Label(frame, text="label_at_0_0")
label_at_0_0.grid(row=0, column=0)
label_at_0_1 = tk.Label(frame, text="not label_at_0_1")
label_at_0_1.grid(row=0, column=1)
label_at_1_0 = tk.Label(frame, text="label_at_1_0")
label_at_1_0.grid(row=1, column=0)
btn_to_move_label = tk.Button(frame, text='move label', command=move_label)
btn_to_move_label.grid(row=1, column=3)
root.mainloop()
I am currently writing a simple logbook application for my sailing holidays. Therefore I wanted to create a small gui for entering data in lines for the logbook.
I am using grid layout with frames and canvas for the main frame, to show a scroll bar, when there are to many lines.
Everything is looking fine, until the command
self.canvasCenter.configure(scrollregion=self.canvasCenter.bbox("all"))
is called. If I comment this line out, the canvas is using the full frame. If this line is active - the canvas is using only 50% of the available screen and date is cut off.
I tried to strip down the code to the necessary things (not using any additional files, configs, classes, etc.). So that it is executable stand alone:
#!/usr/bin/python
# -*- coding: iso-8859-1 -*-
import sys
if sys.version_info.major == 2:
# We are using Python 2.x
import Tkinter as tk
elif sys.version_info.major == 3:
# We are using Python 3.x
import tkinter as tk
#from lib import logBookData
#from config import *
#Titel of the application shown in title bar
appTitle = "My APP"
#Layout geometry (size of the window)
lWidth = 768
lHeight = 900
layoutGeometry = '900x768'
#Colours for foreground and background for labels and entry fields
#headerBG = "Light Blue"
headerBG = "white"
labelBG = "white"
labelFG = "black"
#Number of columns (keep in Sync with headers and width list below!)
cNumber = 14
#Column width for number of columns defined above
cWidth = [5,7,5,5,5,5,5,5,5,5,5,5,5,10]
cHeaders = ["C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "C10", "C11", "C12", "C13", "C14" ]
class logBookGUI(tk.Tk):
def __init__(self,parent):
tk.Tk.__init__(self,parent)
self.parent = parent
self.lineCount = 0
self.initialize()
def initialize(self):
#create a masterframe
self.masterFrame = tk.Frame(self, bg=headerBG, bd=4, relief="groove") #, width = lWidth, height = lHeight)
self.masterFrame.grid(sticky=tk.NSEW)
self.masterFrame.columnconfigure(cNumber, weight=1)
#create Headerframe for Standard Info
self.headerFrame = tk.Frame(self.masterFrame, bg=headerBG, bd=2, relief="groove")
self.headerFrame.grid(row=0, column=0, sticky=tk.NSEW)
self.headerFrame.columnconfigure(cNumber, weight=1)
#Label Bootsname
boatNameLabel = tk.Label(self.headerFrame, text="Bootsname", anchor="w", fg=labelFG,bg=labelBG)
boatNameLabel.grid(column=0, row=0, sticky=tk.NSEW)
#Field Bootsname
self.boatName = tk.StringVar()
self.boatNameEntry = tk.Entry(self.headerFrame,textvariable=self.boatName, width = cWidth[0])
self.boatNameEntry.grid(column=1,row=0, sticky=tk.NSEW)
self.boatName.set(u"Solva")
for i in xrange(cNumber-2):
button = tk.Button(self.headerFrame,text=u"T %s" %i, command=self.OnButtonClick)
button.grid(column=i,row=0, sticky=tk.NSEW)
button = tk.Button(self.headerFrame,text=u"TEST", command=self.OnButtonClick)
button.grid(column=cNumber-2,row=0, sticky=tk.NSEW)
button = tk.Button(self.headerFrame,text=u"Neue Zeile", command=self.newLineClick)
button.grid(column=cNumber-1,row=1, sticky=tk.NSEW)
#create center frame
self.centerFrame = tk.Frame(self.masterFrame, bg=headerBG, bd=2, relief="groove")
self.centerFrame.grid(row=1, column=0, sticky=tk.NSEW)
self.centerFrame.columnconfigure(cNumber, weight=1)
#create a canvas for center frame
self.canvasCenter = tk.Canvas(self.centerFrame)
self.canvasCenter.grid(row=0, column=0, sticky=tk.NSEW)
self.canvasCenter.columnconfigure(cNumber, weight=1)
# Create a vertical scrollbar linked to the canvas.
vsbar = tk.Scrollbar(self.centerFrame, orient=tk.VERTICAL, command=self.canvasCenter.yview)
vsbar.grid(row=0, column=cNumber, sticky=tk.NSEW)
self.canvasCenter.configure(yscrollcommand=vsbar.set)
# Create a frame on the canvas to contain the content.
self.contentFrame = tk.Frame(self.canvasCenter, bg="Red", bd=2, relief="groove")
self.contentFrame.grid(row=0, column=0, sticky=tk.NSEW)
self.contentFrame.columnconfigure(cNumber, weight=1)
column = 0
for header in cHeaders:
label = tk.Label(self.contentFrame, text=header, anchor="w", fg=labelFG,bg=labelBG,borderwidth=2,relief="groove", width = cWidth[column])
label.grid(column = column, row=1, sticky="EW")
column += 1
self.addLine()
# Create canvas window to hold the centerframe.
self.canvasCenter.create_window((0,0), window=self.contentFrame, anchor=tk.NW)
# Update buttons frames idle tasks to let tkinter calculate buttons sizes
self.contentFrame.update_idletasks()
self.canvasCenter.configure(scrollregion=self.canvasCenter.bbox("all"))
self.grid_columnconfigure(cNumber,weight=1)
self.resizable(True,False)
self.update()
self.geometry("%sx%s" % (lHeight, lWidth))
def newLineClick(self):
self.addLine()
def OnButtonClick(self):
pass
def OnPressEnter(self,event):
pass
def addLine(self):
tkLine = []
try:
for i in xrange(cNumber):
self.entryVar = tk.StringVar()
self.entry = tk.Entry(self.contentFrame,textvariable=self.entryVar,width=cWidth[i])
self.entry.grid(column=i, row = self.lineCount + 3, sticky='EW')
tkLine.append(self.entryVar)
self.canvasCenter.configure(scrollregion=self.canvasCenter.bbox("all"))
except IndexError:
print ("Error in config file. Number of columns and given columns do not match - check file config.py")
sys.exit()
self.update()
self.lineCount += 1
if __name__ == "__main__":
app = logBookGUI(None)
app.title(appTitle)
app.mainloop()
Could someone give me an advice how to use scrollregion, so that the whole size of the frame is used?
Many thanks,
Gernot