local variable referenced before assignment - Surely not this difficult - python-3.x

I'm trying to write a script to control movements of a camera. I'm writing it in Thonny on a Raspberry Pi. I receive the following error when trying to move the camera using the GUI buttons. I've asked around and tried troubleshooting the problem but no luck yet.
if anyone can help that'd be awesome.
I appreciate there are alternative workflows to this script but it's me combining an old script with a new GUI so I'd love to see if they could be merged. If not oh well, I'll implement the other workflow.
[Here is the error message from Thonny][1]
from tkinter import *
import RPi.GPIO as GPIO
import time
import datetime, sys, tty, termios
#defining root
root = Tk()
root.title('Operation Little Brother V02')
#setting GPIO board
GPIO.setmode(GPIO.BOARD)
GPIO.setup(3,GPIO.OUT)
servo1 = GPIO.PWM(3, 50)
GPIO.setup(5,GPIO.OUT)
servo2 = GPIO.PWM(5, 50)
#setting servos to off
servo1.start(0)
servo2.start(0)
#user input section
dummy = input('Initiate project. Press Enter')
#setting servos to 90degrees/startup sequence
print('launching start up sequence')
servo1.ChangeDutyCycle(6)
time.sleep(1)
servo1.ChangeDutyCycle(0)
time.sleep(1)
print ('servo 1 test complete')
servo2.ChangeDutyCycle(6)
time.sleep(1)
servo2.ChangeDutyCycle(0)
print ('servo 2 test complete')
# Defining Functions
#x axis movement concept
def x_movement(x_dir):
if x_axis <= limit_x_left and x_axis >= limit_x_right:
x_axis = x_axis + x_dir
servo1.ChangeDutyCycle(x_axis)
time.sleep(0.3)
servo1.ChangeDutyCycle(0)
time.sleep(0.5)
print ('moved camera to position: ' +str(x_axis) + '/' +str(limit_x_left))
return
else:
print ('limits reached')
#y axis movement concept
def y_movement(y_dir):
if y_axis <= limit_y_down and y_axis >= limit_y_up:
y_axis = y_axis + y_dir
servo2.ChangeDutyCycle(y_axis)
time.sleep(0.3)
servo2.ChangeDutyCycle(0)
time.sleep(0.5)
print('moved camera to position: ' +str(y_axis) + '/' +str(limit_y_up))
return y_axis
else:
print ('limits reached')
#centre movement
def centre_movement():
y_axis = 6
servo2.ChangeDutyCycle(6)
servo2.ChangeDutyCycle(0)
time.sleep(0.5)
x_axis = 6
servo1.ChangeDutyCycle(6)
servo1.ChangeDutyCycle(0)
time.sleep(0.5)
print('camera centered to position 6')
return
#off sequence
def off():
servo1.ChangeDutyCycle(0)
servo2.ChangeDutyCycle(0)
servo1.stop()
servo2.stop()
GPIO.cleanup()
print('Whoopty fucking doo it\'s finished')
exit()
#defining limits for x and y axis
limit_x_left = 9
limit_x_right = 3
limit_y_up = 3
limit_y_down = 9
x_axis = 6
y_axis = 6
#frame creation
frame1 = LabelFrame(root, text = 'Welcome to Operation Little Brother', padx = 25, pady = 25, border = 5, fg = '#ffffff', bg = '#3e556b')
#button creation
button1_left = Button(frame1, text = 'Left', padx = 20, pady = 20, fg = 'purple', bg = '#63778a', command = lambda: x_movement(1))
button2_right = Button(frame1, text = 'Right', padx = 20, pady = 20, fg = 'orange', bg = '#63778a', command = lambda: x_movement(-1))
button3_up = Button(frame1, text = 'Up', padx = 20, pady = 20, fg = 'green', command = lambda: y_movement(1))
button4_down = Button(frame1, text = 'Down', padx = 20, pady = 20, fg = 'blue', command = lambda: y_movement(-1))
button5_centre = Button(frame1, text = 'Centre', padx = 20, pady = 20, fg = 'black', command = lambda: centre_movement())
button6_start = Button(frame1, text = 'Start', padx = 10, pady = 10, fg = 'green')
button7_stop = Button(frame1, text = 'Stop', padx = 10, pady = 10, fg = 'red', command = lambda: off())
#positioning the frame
frame1.pack()
#button positioning
button1_left.grid(row = 3, column = 0,)
button2_right.grid(row = 3, column = 2,)
button3_up.grid(row = 2, column = 1)
button4_down.grid(row = 4, column = 1)
button5_centre.grid(row = 3, column = 1)
button6_start.grid(row = 1, column = 0)
button7_stop.grid(row = 1, column = 2)
#Text formatting
button1_left.configure(font='Calibri 15')
button2_right.configure(font='Calibri 15')
button3_up.configure(font='Calibri 15')
button4_down.configure(font='Calibri 15')
button5_centre.configure(font='Calibri 15')
button6_start.configure(font='Calibri 15')
button7_stop.configure(font='Calibri 15')
# Window Loop
root.mainloop()
[1]: https://i.stack.imgur.com/xIc0O.png

Related

Tkinter How to make listbox appear over a frame

making an F1 application where users can type in a driver from the current grid [supported via autofill/suggestions], and then API fetches relevant stats
The issue I'm having is that I want the listbox to appear over another frame (called left_frame). However, what this does is that the listbox goes under left_frame , and not over it. Any thoughts of how to make it appear over the frame?
some approaches that I tried:
used .lift(), but .lift() only seems to work when it's relative to objects in the same frame
since I currently use .grid and placed the listbox in the root frame, I initially tried to put it in top_frame, but it then expands the top_frame. Since I have positioned all frames using .place(), I don't think I can use propagate(False) (I tried it , didn't work)
Here's a picture of the issues
Here's my code so far:
#import necessary modules
from tkinter import *
from tkinter import ttk
from PIL import ImageTk, Image
from tkinter import messagebox
import requests
import json
#set up main window components
root = Tk()
root.title("F1 Desktop Application")
root.geometry("500x600")
root.configure(bg="white")
#since same directory, can just use filename
root.iconbitmap("formula1_logo.ico")
#images
#creating canvas for image to go into
#canvas_f1_logo = Canvas(top_frame, width = 5, height = 5)
#canvas.grid(row = 0, column = 1)
#acquire image
#formula1_logo = ImageTk.PhotoImage(Image.open("formula1_logo.png"))
#resize image
#resized_formula1_logo = formula1_logo.resize((3,3), Image.ANTIALIAS)
#new_formula1_logo = ImageTK.PhotoImage(resized_formula1_logo)
#canvas.create_image(5,5, anchor = NW, image = new_formula1_logo)
#functions
#generate 2022 drivers-list [can scale to drivers-list by changing the]
drivers_list_request = requests.get("http://ergast.com/api/f1/2022/drivers.json")
#initialize empty-list
drivers_list = []
drivers_list_object = json.loads(drivers_list_request.content)
for elements in drivers_list_object["MRData"]["DriverTable"]["Drivers"]:
drivers_list.append(elements["givenName"] + " " + elements["familyName"])
#set up frames [main frames, can put frames within frames if needed]
#frame for search bar + magnifying glass
top_frame = LabelFrame(root, padx = 80, pady = 15)
top_frame.place(relx = 0.5, rely = 0.2, anchor = CENTER)
header_label = Label(top_frame, text = "F1 2022 Drivers App", pady = 20, font = ("Arial bold",14))
header_label.grid(row = 0, column = 0, pady = 2 )
search_button = Button(top_frame, text = "search", padx = 2, pady = 2)
search_button.grid(row = 1, column = 1)
# Update the Entry widget with the selected item in list
def check(e):
v= entry.get()
if v=='':
hide_button(menu)
else:
data=[]
for item in drivers_list:
if v.lower() in item.lower():
data.append(item)
update(data)
show_button(menu)
def update(data):
# Clear the Combobox
menu.delete(0, END)
# Add values to the combobox
for value in data:
menu.insert(END,value)
def fillout(event):
try:
entry.delete(0,END)
entry.insert(0,menu.get(menu.curselection()))
#handle a complete deletion of entry-box via cursor double tap
except:
pass
def hide_button(widget):
widget.grid_remove()
def show_button(widget):
widget.grid()
# Create an Entry widget
entry= Entry(top_frame)
entry.grid(row = 1, column = 0)
entry.bind('<KeyRelease>',check)
# Create a Listbox widget to display the list of items
menu= Listbox(root)
menu.grid(row = 2, column = 0, padx = 165, pady = 165)
menu.bind("<<ListboxSelect>>",fillout)
menu.lift()
# Add values to our combobox
hide_button(menu)
left_frame = LabelFrame(root, padx = 30, pady = 30)
left_frame.place(relx = 0.24, rely = 0.5, anchor = CENTER)
bottom_left_frame = LabelFrame(root, padx = 30, pady = 30)
bottom_left_frame.place(relx = 0.24, rely = 0.82, anchor = CENTER)
bottom_right_frame = LabelFrame(root, padx = 30, pady = 30)
bottom_right_frame.place(relx = 0.6, rely = 0.82)
basic_info = Label(left_frame, text = "Basic Info ", font = ("Arial bold",14))
basic_info.grid(row = 0, column = 0, pady = 3)
full_name = Label(left_frame, text = "Full Name : ")
full_name.grid(row = 1, column = 0, pady = 2)
driver_code = Label(left_frame, text = "Driver Code : ")
driver_code.grid(row = 2, column = 0, pady = 2)
nationality = Label(left_frame, text = "Nationality : ")
nationality.grid(row = 3, column = 0, pady = 2)
F1_career = Label(bottom_left_frame, text = "F1 Career ", font = ("Arial bold",14))
F1_career.grid(row = 0, column = 0, pady = 3)
wins = Label(bottom_left_frame, text = "Wins :")
wins.grid(row = 1, column = 0, pady = 2)
poles = Label(bottom_left_frame, text = "Poles :")
poles.grid(row = 2, column = 0, pady = 2)
drivers_championships = Label(bottom_left_frame, text = "Championships :")
drivers_championships.grid(row = 3, column = 0 , pady = 2)
F1_22_stats = Label(bottom_right_frame, text = "F1 22 Stats", font = ("Arial bold",14))
F1_22_stats.grid(row = 0, column = 0, pady = 3)
root.mainloop()
would appreciate the help!

Problem storing date in mysql with python tkinter

What is the possible problem because every time I select a date there is an error which is "Column count doesn't match value count and row 1". The columns are correct and I also converted the date entry to string. But there it comes out. I would like to store it in the MySQL database. Hope someone can help thank you in advance.
Here's my full code:
from tkinter import *
from tkinter.ttk import Combobox
from tkcalendar import DateEntry
from tkinter import ttk
from tkinter import messagebox
import mysql.connector
def addData():
try:
full_name = full_name_entry.get()
if full_name == "":
messagebox.showerror(title = "Save Record Error", message = "You must fill field first")
else:
connection = mysql.connector.connect(
host = 'localhost',
username = 'root',
password = '',
database = 'scratch_database'
)
my_cursor = connection.cursor()
my_cursor.execute("insert into scratch_table values(%s,%s,%s,%s,%s)",
(fullName.get(),
srProject.get(),
contractStart.get(),
contractEnd.get(),
stat.get()
))
connection.commit()
connection.close()
messagebox.showinfo(title = "Information", message = "Record Saved!")
except Exception as e:
messagebox.showerror(title = "Scratch Data", message = e)
def databaseConnection():
try:
connection = mysql.connector.connect(
host = 'localhost',
username = 'root',
password = '',
database = 'scratch_database'
)
my_cursor = connection.cursor()
messagebox.showinfo(title = "Information", message = "You are connected to database")
connection.commit()
connection.close()
except Exception as e:
messagebox.showerror(title = "Connection Error", message = e)
def mainWindow():
window = Tk()
window.config(bg = 'white')
window.title("Sample Table for SR Data")
window.resizable(0,0)
window.geometry('1212x771')
global fullName
global srProject
global contractStart
global contractEnd
global stat
fullName = StringVar()
srProject = StringVar()
contractStart = StringVar()
contractEnd = StringVar()
stat = StringVar()
# FULLNAME LABEL
full_name = Label(window, text = "Full Name", font = ('Arial', 12), bg = 'white')
full_name.place(x = 30, y = 63)
global full_name_entry
# FULLNAME ENTRY
full_name_entry = Entry(window, font = ('Arial', 12), width = 30, highlightbackground = 'gray', highlightcolor = 'black',
highlightthickness = 1, bd = 0, textvariable = fullName)
full_name_entry.place(x = 34, y = 101)
# PROJECTS LABEL
projects = Label(window, text = "Positions", font = ('Arial', 12), bg = 'white')
projects.place(x = 30, y = 156)
# POSITIONS OPTIONS
projects_options = ['Agricultural Situation Report', 'ASPBI', 'BLPS', 'BPCS', 'CPH', 'Census Evaluation Survey',
'Cities and Municipalities Competitive Index','CLPS', 'CSS', 'CBMS', 'Consumer Expectation Survey',
'Other Crop Survey', 'PCPS', 'PCSS', 'PPS', 'QaFS/QiFS', 'QSPBI', 'WSP/RPS', 'SICT', 'SOF', 'UGBSEA',
'ULE', 'CPS', 'CDSPDP', 'CLPS', 'SCMDV for 2021 PPCM', 'CDC', 'Quarterly Crops Production Survey',
'2021 CLPS','MPCSRS/PCSS/CSS 2021', 'January 2022 FPS'
]
# POSITIONS COMBOBOX
projects_combo_box = Combobox(window, values = projects_options, width = 28, font = ('Arial', 12), cursor = 'hand2', textvariable = srProject)
projects_combo_box.place(x = 34, y = 192)
# PREVENTS A TYPING VALUE IN COMBO BOX
projects_combo_box['state'] = 'readonly'
# START OF CONTRACT LABEL
start_of_contract = Label(window, text = "Start of Contract", font = ('Arial', 12), bg = 'white')
start_of_contract.place(x = 30, y = 261)
# START OF CONTRACT DATE TIME PICKER
start_of_contract_date = DateEntry(window, selectmode = 'day', year = 2022, month = 1, day = 1, cursor = 'hand2',
font = ('Arial', 12), width = 28, textvariable = contractStart)
start_of_contract_date.place(x = 34, y = 299)
# END OF CONTRACT LABEL
end_of_contract = Label(window, text = "End of Contract", font = ('Arial', 12), bg = 'white')
end_of_contract.place(x = 30, y = 362)
# END OF CONTRACT DATE TIME PICKER
end_of_contract_date = DateEntry(window, selectmode = 'day', year = 2022, month = 1, day = 1, cursor = 'hand2',
font = ('Arial', 12), width = 28, textvariable = contractEnd)
end_of_contract_date.place(x = 34, y = 400)
# STATUS LABEL
status = Label(window, text = "Positions", font = ('Arial', 12), bg = 'white')
status.place(x = 30, y = 464)
# STATUS OPTIONS
status_options = ['Active', 'Inactive', 'Terminated', 'Blacklisted']
# STATUS COMBOBOX
status_combo_box = Combobox(window, values = status_options, width = 28, font = ('Arial', 12), cursor = 'hand2', textvariable = stat)
status_combo_box.place(x = 34, y = 500)
# PREVENTS A TYPING VALUE IN COMBO BOX
status_combo_box['state'] = 'readonly'
# SAVE BUTTON
save = Button(window, text = "Save", font = ('Arial', 12), padx = 43, pady = 5, cursor = 'hand2', bg = 'green', fg = 'white', bd = 0,
activebackground = 'green', activeforeground = 'white', command = addData)
save.place(x = 34, y = 573)
# EDIT BUTTON
edit = Button(window, text = "Edit", font = ('Arial', 12), padx = 45, pady = 5, cursor = 'hand2', bg = 'orange', fg = 'white',
activebackground = 'orange', activeforeground = 'white', bd = 0)
edit.place(x = 180, y = 573)
# DELETE BUTTON
delete = Button(window, text = "Delete", font = ('Arial', 12), padx = 45, pady = 5, cursor = 'hand2', bg = 'red', fg = 'white',
activebackground = 'red', activeforeground = 'white', bd = 0)
delete.place(x = 93, y = 648)
# CONNECTION BUTTON
connection_button = Button(window, text = "Check Stat", font = ('Arial', 12), padx = 10, pady = 5, cursor = 'hand2', bg = 'blue', fg = 'white',
activebackground = 'blue', activeforeground = 'white', bd = 0, command = databaseConnection)
connection_button.place(x = 1064, y = 648)
# SEARCH LABEL
search = Label(window, text = "Search", font = ('Arial', 12), bg = 'white')
search.place(x = 878, y = 44)
# SEARCH ENTRY
search_entry = Entry(window, font = ('Arial', 12), width = 15, highlightbackground = 'gray', highlightcolor = 'black',
highlightthickness = 1, bd = 0)
search_entry.place(x = 966, y = 41)
# Create Treeview Frame
tree_frame = Frame(window)
tree_frame.pack(pady=20)
# Treeview Scrollbar
tree_scroll = Scrollbar(tree_frame)
tree_scroll.pack(side=RIGHT, fill=Y)
# Create Treeview
my_tree = ttk.Treeview(tree_frame, yscrollcommand=tree_scroll.set, selectmode="extended")
# Pack to the screen
my_tree.pack(side= LEFT)
#Configure the scrollbar
tree_scroll.config(command=my_tree.yview)
# Define Our Columns
my_tree['columns'] = ("SRID", "fullname", "projects", "startofcontract", "endofcontract", "status")
# Formate Our Columns
my_tree.column("#0", width=0, stretch=NO)
my_tree.column("SRID", anchor=W, width=140)
my_tree.column("fullname", anchor=CENTER, width=100)
my_tree.column("projects", anchor=W, width=140)
my_tree.column("startofcontract", anchor=CENTER, width=140)
my_tree.column("endofcontract", anchor=W, width=140)
my_tree.column("status", anchor=CENTER, width=140)
# Create Headings
my_tree.heading("#0", text="", anchor=W)
my_tree.heading("SRID", text="SRID", anchor=W)
my_tree.heading("fullname", text="FullName", anchor=CENTER)
my_tree.heading("projects", text="Projects", anchor=W)
my_tree.heading("startofcontract", text = "Start", anchor=W)
my_tree.heading("endofcontract", text = "End", anchor=W)
my_tree.heading("status", text = "Status", anchor=W)
window.mainloop()
mainWindow()

Tkinter Trace Method returns 3 variables when 0 are expected

I am trying to make a dynamic gui that changes its labels based on what value is selected in a combo box. I am trying to employ the .trace method to accomplish this. I am receiving the following error with my current set up "area_labels takes 0 positional arguments but 3 were given)
I have attached the relevant parts of my code below.
from tkinter import *
import tkinter as tk
from tkinter import ttk
window = Tk()
window.geometry('1300x700')
window.title('Volumetric Calculator')
areastcboxv = StringVar()
areastcbox = ttk.Combobox(window, textvariable = areastcboxv, values = ('Discrete','Normal','Truncated Normal', 'Log Normal'))
areastcbox.grid(row = 1, column = 2)
areastcbox.set('Discrete')
areastcboxv.trace("w", area_labels)
def area_labels():
if areastcboxv.get() == "Discrete":
lvlabel = Label(text = 'Base Case Value', fg = 'black', bg = 'white', width = 17 ).grid(row = 0, column = 3)
bvlabel = Label(text = 'Standard Dev', fg = 'black', bg = 'white', width = 17 ).grid(row = 0, column = 4)
hvlabel = Label(text = 'High Value', fg = 'black', bg = 'white', width = 17).grid(row = 0, column = 5)
lplabel = Label(text = 'Low Probability', fg = 'black', bg = 'white', width = 17).grid(row = 0, column = 6)
bplabel = Label(text = 'Base Probability', fg = 'black', bg = 'white', width = 17).grid(row = 0, column = 7)
hplabel = Label(text = 'High Probability', fg = 'black', bg = 'white', width = 17, state = DISABLED ).grid(row = 0, column = 8)
elif areastcboxv.get() == "Normal":
lvlabel = Label(text = 'Base Case Value', fg = 'black', bg = 'white', width = 17 ).grid(row = 0, column = 3)
bvlabel = Label(text = 'Standard Dev', fg = 'black', bg = 'white', width = 17 ).grid(row = 0, column = 4)
hvlabel = Label(text = 'High Value', fg = 'black', bg = 'white', width = 17, state = DISABLED ).grid(row = 0, column = 5)
lplabel = Label(text = 'Low Probability', fg = 'black', bg = 'white', width = 17, state = DISABLED ).grid(row = 0, column = 6)
bplabel = Label(text = 'Base Probability', fg = 'black', bg = 'white', width = 17, state = DISABLED ).grid(row = 0, column = 7)
hplabel = Label(text = 'High Probability', fg = 'black', bg = 'white', width = 17, state = DISABLED ).grid(row = 0, column = 8)
elif areastcboxv.get() == "Truncated Normal":
pass
elif areastcboxv.get() == "Log Normal":
pass
window.mainloop()
The trace will supply three arguments.
change your function to
area_labels(*event)
or
area_labels(a,b,c)
Look here for for an explaination What are the arguments to Tkinter variable trace method callbacks?
import tkinter as tk
from tkinter import ttk
def selection(*trace_event):
print('the trace arguments',trace_event)
chosen['text'] = options.get()
ROOT = tk.Tk()
val = tk.StringVar()
options = ttk.Combobox(textvariable=val,
values=('a','b','c'))
options.grid()
val.trace('w', selection)
chosen = tk.Label(text='No selection')
chosen.grid()
ROOT.mainloop()

How to change background color in ttk python

I've made a simple gui age converter app but i want to change its bg color to black.
The problem is in the ttk frame.i don't know how to configure its bg color.
I have tried different methods but that didn't work.
i would be grateful if you guys could help.
here is the code
from tkinter import *
from tkinter import ttk
from PIL import Image
def calculate(*args):
try:
age_sec = int(age.get())
age_sec = age_sec * 12 * 365 * 24 * 60 * 60
age_seconds.set(age_sec)
except:
age_seconds.set('Either the field is empty or \n value is not numeric.')
root = Tk()
root.title("Converter")
root.configure(background="black")
mainframe = ttk.Frame(root, padding = "6 6 12 12")
mainframe.grid(column = 0, row = 0, sticky = (N, W, E, S))
mainframe.columnconfigure(0, weight = 1)
mainframe.rowconfigure(0, weight = 1)
#mainframe['borderwidth'] = 2
#mainframe['relief'] = 'groove'
age = StringVar()
age_seconds = StringVar()
ttk.Label(mainframe, foreground = "#4D4E4F", text = "Enter your Age: ").grid(column = 1, row = 1, sticky = E)
age_entry = ttk.Entry(mainframe, width = 30, textvariable = age)
age_entry.grid(column = 2, row = 1, sticky = (W, E))
ttk.Label(mainframe, foreground = "#4D4E4F", text = "your age in seconds is ").grid(column = 1, row = 2, sticky = (E))
ttk.Label(mainframe, textvariable = age_seconds, background = "lightyellow", foreground = "#727475", width = 30).grid(column = 2, row = 2, sticky = W)
#Mouse Events...\\
butt_image = PhotoImage(file = 'images.gif')
ttk.Button(mainframe, compound = TOP, text = "Hit Now", image =butt_image, cursor = "hand2", width= 30, command = calculate).grid(column = 2, row = 4, sticky = W)
l2 = ttk.Label(mainframe,foreground = "#4D4E4F", text = "Mouse Events: ").grid(column = 1, row = 3, sticky = E)
l = ttk.Label(mainframe,background = "lightyellow", foreground = "#727475", text = 'Measurement is starting...', width = 30)
l.grid(column = 2, row = 3, sticky = W)
l.bind('<Enter>', lambda e: l.configure(text = 'Moved Mouse Inside'))
l.bind('<Leave>', lambda e: l.configure(text = 'Mouse Moved Out'))
l.bind('<1>', lambda e: l.configure(text = 'left Mouse clicked'))
l.bind('<Double-1>', lambda e: l.configure(text = 'Double clicked'))
l.bind('<B1-Motion>', lambda e: l.configure(text = 'Left button drag to %d, %d' %(e.x, e.y)))
image = PhotoImage(file = 'waves.gif')
ttk.Label(mainframe, compound = CENTER, text = "Image text", font = ('roman', 9, 'normal'), foreground ='green', image = image).grid(column = 3, row = 1, sticky = (N, E))
#if '__name__' == '__main__':
for child in mainframe.winfo_children(): child.grid_configure(padx = 15, pady = 15)
age_entry.focus()
root.bind('<Return>', calculate)
root.mainloop()
A ttk.Frame does not have a background / bg option. To change it you need to use style.
See ttk.Frame Info
If you don't really need to use a ttk.Frame you can just switch to a tkinter.Frame

Odd grid sizing behaviour

I have been using tkinter's grid geometry manager and have configured all the rows and columns to weight = 1. The problem comes when I try to resize a Tk() window. When I resize it vertically only, the width of widgets and the proportion of column widths also change despite their equal weight. Furthermore, the width of the columns isn't in the desired proportions (i.e. all equal) before doing any resizing - to be precise the first column (with labels and buttons) is as wide as other two (holding a canvas with columnspan = 2 and two labels).
I think the problem is somehow connected to the PiSimulator._adjust_sizes function which dynamically changes the font or to the use of the canvas with a columnspan of 2.
Here's my code:
import tkinter as tk
from tkinter import font
class PiSimulator(tk.Frame):
def __init__(self, root, **kwargs):
super(PiSimulator, self).__init__(root, **kwargs)
self.root = root
self.root.title = 'Crtac krugova'
self.root.minsize(width = 600, height = 400)
self.pack(fill = 'both', expand = 1)
self.custom_font = font.Font(size = 20)
self.bind('<Configure>', self._adjust_sizes)
self.populate()
return
def populate(self):
tk.Label(self, text = 'Radijus:', font = self.custom_font, relief = 'raised',\
fg = 'green').grid(sticky='nswe', row = 0, column = 0)
self.radius = tk.IntVar()
tk.Spinbox(self, from_ = 1, to = 16, font = self.custom_font, textvariable = self.radius).grid(row = 1, column = 0)
tk.Label(self, text = 'Greška', font = self.custom_font, relief = 'raised', anchor='w',\
padx = 5, pady = 5, fg = 'green').grid(sticky='nswe', row = 0, column = 1)
self.error = tk.DoubleVar(0.0)
tk.Label(self, textvariable = self.error, font = self.custom_font, relief = 'raised',\
anchor='e', pady = 5, fg = 'green').grid(row = 0, column = 2, sticky='nswe')
self.canvas = PiCanvas(self, highlightthickness = 0)
self.canvas.grid(row = 1, rowspan = 5, column = 1, columnspan = 2, padx = 5, pady = 5, sticky='nswe')
tk.Button(self, text = 'Nacrtaj', font = self.custom_font, command = lambda: self.canvas.draw(self.radius.get())).grid(\
column = 0, row = 2, sticky='nswe')
tk.Button(self, text = 'Izbriši', font = self.custom_font, command = self.canvas.clear ).grid(\
column = 0, row = 3, sticky='nswe')
tk.Label(self, text = 'POVRŠINA', relief = 'groove', font = self.custom_font).grid(column = 0, row = 4, sticky='nswe')
self.area = tk.IntVar(0)
tk.Label(self, textvariable = self.area, relief = 'groove', font = self.custom_font).grid(column = 0, row = 5, sticky='nswe')
for i in range(3):
self.columnconfigure(i, weight = 1)
for i in range(6):
self.rowconfigure(i, weight = 1)
return
def _adjust_sizes(self, event):
new_font = int(event.height/15) - 2
self.custom_font.configure(size = new_font)
return
class PiCanvas(tk.Canvas):
def __init__(self, root, **kwargs):
super(PiCanvas, self).__init__(root, background = 'white', relief = 'groove', **kwargs)
self.root = root
self.cubes = []
self.circle = None
def draw(self, radius):
self.clear()
c_width = self.winfo_width()
c_height = self.winfo_height()
self.grid_side = int(min([c_width, c_height]))
self.grid_side-= 10
self.v_offset = (c_height - self.grid_side)/2
self.h_offset = (c_width - self.grid_side)/2
self.cube_side = self.grid_side/(2*radius)
vertix_coord = lambda x, x_cor, y_cor: x_cor*self.h_offset+y_cor*self.v_offset+x*self.cube_side
for i in range(2*radius):
new_line = []
for j in range(2*radius):
cube = self.create_rectangle(vertix_coord(i, 1, 0), vertix_coord(j, 0, 1),\
vertix_coord(i+1, 1, 0), vertix_coord(j+1, 0, 1), tag = 'unused')
new_line.append(cube)
self.cubes.append(new_line)
self.circle = self.create_oval(vertix_coord(0,1,0), vertix_coord(0,0,1),\
vertix_coord(2*radius,1,0), vertix_coord(2*radius,0,1),width = 2)
self.color_border_cubes()
print(self.circle)
def color_border_cubes(self):
circle_coords = self.coords(self.circle)
print(circle_coords)
for i in self.cubes:
for j in i:
cube_coords = self.coords(j)
if self.circle in self.find_overlapping(*cube_coords) + self.find_enclosed(*circle_coords):
self.itemconfigure(j, fill = 'green')
def clear(self):
self.cubes = []
self.circle = None
self.delete('all')
return
root = tk.Tk()
a=PiSimulator(root)
root.mainloop()

Resources