Related
currently working on an API-based F1 drivers' app using Python and Tkinter.
The issue I'm facing is that contents from previous searches appear on forthcoming content.
Visually, the issue can be best represented here, where the new content appears on top of the old content, which is no good.
To solve this problem, I know that logically, there should be some approach where when user presses search_button, the button should be attempting to clear the previous search's content in main_frame and then recreate main_frame with the new content.
Generally, it's not too difficult to clear content in a frame, since that's through using w_info and the .destroy() method, but I don't know how to recreate a frame with new content. In other words, I'm having trouble programming out the logic (perhaps the logic should be clearer or there should be different logic)
Here's the code:
#Go to
from tkinter import *
from tkinter import ttk
from PIL import ImageTk, Image
from tkinter import messagebox
import requests
import json
root = Tk()
root.geometry("800x300")
root.title("F1 Desktop Application")
root.iconbitmap("formula1_logo.ico")
#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"])
# Update the Entry widget with the selected item in list
def check(e):
v= entry_box.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_box.delete(0,END)
entry_box.insert(0,menu.get(menu.curselection()))
hide_button(menu)
#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()
def full_name():
lower_user_input = grab_user_input()
response = requests.get("http://ergast.com/api/f1/drivers/{}.json".format(lower_user_input))
response_object = json.loads(response.content)
name = response_object["MRData"]["DriverTable"]["Drivers"][0]["givenName"] + " " + response_object["MRData"]["DriverTable"]["Drivers"][0]["familyName"]
driver_name_label.configure(text = name)
def team():
lower_user_input = grab_user_input()
response = requests.get("http://ergast.com/api/f1/current/drivers/{}/constructors.json".format(lower_user_input))
response_object = json.loads(response.content)
team = response_object["MRData"]["ConstructorTable"]["Constructors"][0]["name"]
team_api = Label(main_frame, text = team, font = ("Arial", 10))
team_api.grid(row = 1, column = 1)
def driver_code():
lower_user_input = grab_user_input()
response = requests.get("http://ergast.com/api/f1/drivers/{}.json".format(lower_user_input))
response_object = json.loads(response.content)
code = response_object["MRData"]["DriverTable"]["Drivers"][0]["code"]
code_api = Label(main_frame, text = code, font = ("Arial", 10))
code_api.grid(row = 3, column = 1, sticky = W)
def nationality():
lower_user_input = grab_user_input()
response = requests.get("http://ergast.com/api/f1/drivers/{}.json".format(lower_user_input))
response_object = json.loads(response.content)
nationality = response_object["MRData"]["DriverTable"]["Drivers"][0]["nationality"]
nationality_api = Label(main_frame, text = nationality, font = ("Arial", 10))
nationality_api.grid(row = 2, column = 1, sticky = W)
def wins():
lower_user_input = grab_user_input()
response = requests.get("http://ergast.com/api/f1/drivers/{}/results/1.json".format(lower_user_input))
response_object = json.loads(response.content)
wins = response_object["MRData"]["total"]
wins_api = Label(main_frame, text = wins, font = ("Arial", 10))
wins_api.grid(row = 4, column = 1, sticky = W)
def poles():
lower_user_input = grab_user_input()
response = requests.get("http://ergast.com/api/f1/drivers/{}/qualifying/1.json".format(lower_user_input))
response_object = json.loads(response.content)
poles = response_object["MRData"]["total"]
poles_api = Label(main_frame, text = poles, font = ("Arial", 10))
poles_api.grid(row = 2, column = 3, sticky = W, padx = 15)
def podiums():
lower_user_input = grab_user_input()
#podiums is sum of 1st, 2nd, 3rd place finishes
#####DRY principle; let's reuse the code from wins()
######noticing how maybe should create a separate function which "places" the widget
#######for now, reuse the code
#1st place finishes
response = requests.get("http://ergast.com/api/f1/drivers/{}/results/1.json".format(lower_user_input))
response_object = json.loads(response.content)
#convert wins to int
wins = int(response_object["MRData"]["total"])
#2nd place finishes
response_ii = requests.get("http://ergast.com/api/f1/drivers/{}/results/2.json".format(lower_user_input))
response_ii_object = json.loads(response_ii.content)
response_ii_amount = int(response_ii_object["MRData"]["total"])
#3rd place finishes
response_iii = requests.get("http://ergast.com/api/f1/drivers/{}/results/3.json".format(lower_user_input))
response_iii_object = json.loads(response_iii.content)
response_iii_amount = int(response_iii_object["MRData"]["total"])
podiums = str(wins + response_ii_amount + response_iii_amount)
podiums_api = Label(main_frame, text = podiums, font = ("Arial", 10))
podiums_api.grid(row = 1, column = 3, padx = 15, sticky = W)
def championships():
lower_user_input = grab_user_input()
response = requests.get("http://ergast.com/api/f1/drivers/{}/driverStandings/1/seasons.json".format(lower_user_input))
response_object = json.loads(response.content)
championships = response_object["MRData"]["total"]
championships_api = Label(main_frame, text = championships, font = ("Arial", 10))
championships_api.grid(row = 3, column = 3, padx = 15, sticky = W)
def standing():
lower_user_input = grab_user_input()
response = requests.get("http://ergast.com/api/f1/current/drivers/{}/driverStandings.json".format(lower_user_input))
response_object = json.loads(response.content)
position = response_object["MRData"]["StandingsTable"]["StandingsLists"][0]["DriverStandings"][0]["position"]
points = response_object["MRData"]["StandingsTable"]["StandingsLists"][0]["DriverStandings"][0]["points"]
standing = "{} ({} pts)".format(position, points)
standing_api = Label(main_frame, text = standing, font = ("Arial", 10))
standing_api.grid(row = 4, column = 3, padx = 15, sticky = W)
def grab_user_input():
user_input = entry_box.get()
lower_user_input = user_input.lower().split(" ")[1]
return lower_user_input
def search():
#slow run-time is simply due to the multiple api calls made
#perhaps less-so due to not completely following DRY principles
full_name()
team()
driver_code()
nationality()
wins()
poles()
podiums()
championships()
standing()
show_button(main_frame)
left_frame = LabelFrame(root, width = 275, height = 300)
left_frame.grid(row = 1, column = 0, sticky = SE)
left_frame.grid_propagate(False)
search_label = Label(left_frame, text = "Search Driver", font = ("Arial bold", 12))
search_label.grid(row = 0, column = 0, pady = 10)
entry_box = Entry(left_frame, bd = 5)
entry_box.grid(row = 1, column = 0, padx = 35, pady = 40)
entry_box.bind('<KeyRelease>',check)
search_button = Button(left_frame, text = "search", command = search)
search_button.grid(row = 1, column = 1, padx = 15)
menu= Listbox(left_frame, height = 7)
menu.grid(row = 2, column = 0)
menu.bind("<<ListboxSelect>>",fillout)
main_frame = LabelFrame(root, width = 575, height = 300)
main_frame.grid(row = 1, column = 1, sticky = SE)
main_frame.grid_propagate(False)
driver_name_label = Label(main_frame, text = "Driver", font = ("Arial", 15))
driver_name_label.grid(row = 0, column = 0,pady = 30)
team_label = Label(main_frame, text = "TEAM", font = ("Arial", 10))
team_label.grid(row = 1, column = 0, sticky = W)
nationality_label = Label(main_frame, text = "NATIONALITY", font = ("Arial", 10))
nationality_label.grid(row = 2, column = 0, sticky = W)
driver_code_label = Label(main_frame, text = "DRIVER CODE", font = ("Arial", 10))
driver_code_label.grid(row = 3, column = 0, sticky = W)
wins_label = Label(main_frame, text = "WINS", font = ("Arial", 10))
wins_label.grid(row = 4, column = 0, sticky = W)
podiums_label = Label(main_frame, text = "PODIUMS", font = ("Arial", 10))
podiums_label.grid(row = 1, column = 2, sticky = W, padx = 15)
poles_label = Label(main_frame, text = "POLES", font = ("Arial", 10))
poles_label.grid(row = 2, column = 2, sticky = W, padx = 15)
world_championships_label = Label(main_frame, text = "WORLD CHAMPIONSHIPS", font = ("Arial", 10))
world_championships_label.grid(row = 3, column = 2, padx = 15, sticky = W)
current_standing_label = Label(main_frame, text = "F1 2022 STANDING", font = ("Arial", 10))
current_standing_label.grid(row = 4, column = 2, padx = 15, sticky = W)
hide_button(menu)
hide_button(main_frame)
root.mainloop()
Would appreciate the help! If there are any follow-up questions for clarity, let me know!
Thanks, Safwan
I'm using grid_remove() and grid() command to hide/show the widget but the result is the other widget is move out of the original position.
How to hide/show the widget without moving widget
Example:
from tkinter import *
from tkinter import ttk
GUI = Tk()
GUI.title("myTest")
GUI.geometry("700x700")
Nameget = StringVar()
Priceget = StringVar()
Quantityget = StringVar()
Unitget = StringVar()
Partnumget = StringVar()
L_Partnum = ttk.Label(GUI, text = 'Part number')
L_Partnum.grid(row = 0, column = 0)
L_namme = ttk.Label(GUI, text = 'Name')
L_namme.grid(row = 0, column = 1)
L_quan = ttk.Label(GUI, text = 'Quantity')
L_quan.grid(row = 1, column = 2)
L_quan.grid_remove()
L_price = ttk.Label(GUI, text = 'Price')
L_price.grid(row = 3, column = 3)
E_partnum = ttk.Entry(GUI, textvariable = Partnumget)
E_partnum.grid(row = 1, column = 0)
E_namme = ttk.Entry(GUI,textvariable = Nameget)
E_namme.grid(row = 1, column = 1)
E_unit = ttk.Entry(GUI,textvariable = Unitget)
E_quan = ttk.Entry(GUI,textvariable = Quantityget)
E_quan.grid(row = 2, column = 2)
E_quan.grid_remove()
E_price = ttk.Entry(GUI,textvariable = Priceget)
E_price.grid(row = 4, column = 3)
I_check_vat = IntVar()
def d_check_vat_1():
E_partnum.focus()
if I_check_vat.get() == 1:
L_quan.grid()
E_quan.grid()
elif I_check_vat.get() == 0:
L_quan.grid_remove()
E_quan.grid_remove()
C_CHECK_VAT = ttk.Checkbutton(GUI, text="click here to see the result", variable=I_check_vat, command=d_check_vat_1)
C_CHECK_VAT.grid(row = 5, column = 0)
GUI.mainloop()
Before clicking:
After clicking:
image with the expected output:
The problem is grid() does not take up empty space by default, it gives the last empty row/col to the widget(if previous rows before it are empty).
So what you can do is, set minimum space for your column and row so that those space will remain empty, so change your function to:
def d_check_vat_1():
E_partnum.focus()
if I_check_vat.get():
L_quan.grid(row=2, column=2)
E_quan.grid(row=3, column=2)
width = E_quan.winfo_reqwidth() # Get widget width
height = L_quan.winfo_reqheight() # Get widget height
GUI.rowconfigure(2,minsize=height) # Now apply the values
GUI.rowconfigure(3,minsize=height)
GUI.columnconfigure(2,minsize=width)
else:
L_quan.grid_remove()
E_quan.grid_remove()
Now its dynamic as well, it takes the width of widget and applies that as the minsize of that row so that row will have that empty space.
This script when run, opens a window that is divided into 3 frames:
A big frame into which data will be shown (label widgets).
A smaller frame underneath it with user input widgets.
A small frame in the bottom-right corner with a textbox widget.
The big frame will have a lot of data (= label-widgets) so I need it to be scrollable (vertically).
This I have done by creating a canvas widget alonside a scrollbar widget. In the canvas, a frame widget is placed.
Everything seems to be working, however my resizing function does not.
My frame widget does not get its dimensions updated! This is probably because of an error that I can't manage to fix.
Fundamental question:
The script gives an error on the "lambda: resize_frame(self)" command on line 43. How do i fix this?
Side-note: My issue probably has more to do with an improper binding on the canvas widget. Because I'm not sure I wanted to give enough context (script).
Many thanks in advance.
from Tkinter import *
import math
class Processing(Toplevel):
def __init__(self, master, *args, **kwargs):
Toplevel.__init__(self, master)
self.master = master
self.title("Process Window")
for r in range(6):
self.rowconfigure(r, weight = 1)
for c in range(4):
self.columnconfigure(c, weight = 1)
### WINDOW size and position definitions ###
ScreenSizeX = master.winfo_screenwidth()
ScreenSizeY = ( master.winfo_screenheight() - 75 ) #about 75pixels for taskbar on bottom of screen (Windows)
ScreenRatio = 0.9
FrameSizeX = int(ScreenSizeX * ScreenRatio)
FrameSizeY = int(ScreenSizeY * ScreenRatio)
FramePosX = (ScreenSizeX - FrameSizeX)/2
FramePosY = (ScreenSizeY - FrameSizeY)/2
self.geometry("%sx%s+%s+%s"%(FrameSizeX,FrameSizeY,FramePosX,FramePosY))
### Creating 3 "sub-frames" ###
# Frame 1 - canvas container with scrollbar#
self.Canvas1 = Canvas(self, bg = "white")
self.Canvas1.grid(row = 0, column = 0, rowspan = 5, columnspan = 4, sticky = N+E+S+W)
self.Canvas1.rowconfigure(1, weight = 1)
self.Canvas1.columnconfigure(1, weight = 1)
self.myscrollbar=Scrollbar(self, orient = "vertical", command = self.Canvas1.yview)
self.Canvas1.configure(yscrollcommand = self.myscrollbar.set)
self.myscrollbar.grid(row = 0, column = 4, rowspan = 5, sticky = N+S)
# Frame 1 - Frame widget in canvas #
self.Frame1 = Frame(self.Canvas1, bg = "white")
self.Frame1.rowconfigure(0, weight = 1)
for c in range(2):
self.Frame1.columnconfigure(1 + (2 * c), weight = 1)#1,3 - columns for small icons in the future
for cb in range(3):
self.Frame1.columnconfigure((cb * 2), weight = 9)#0,2,4 - columns for data
self.CFrame1 = self.Canvas1.create_window(0, 0, window = self.Frame1, width = FrameSizeX, anchor = N+W)
self.Canvas1.bind("<Configure>", lambda: resize_frame(self)) # !!!!! Doesn't work & gives error !!!!!! #
self.Frame1.bind("<Configure>", lambda: scrollevent(self))
self.Canvas1.config(scrollregion=self.Canvas1.bbox("all"))
# Frame 2 #
self.Frame2 = Frame(self, bg= "yellow")
self.Frame2.grid(row = 5, column = 0, rowspan = 1, columnspan = 3, sticky = W+E+N+S)
for r in range(3):
self.Frame2.rowconfigure(r, weight=1)
for c in range(3):
self.Frame2.columnconfigure(c, weight = 1)
# Frame 3 #
self.Frame3 = Frame(self)
self.Frame3.grid(row = 5, column = 3, rowspan = 1, columnspan = 2, sticky = W+E+N+S)
self.Frame3.rowconfigure(0, weight = 1)
self.Frame3.columnconfigure(0, weight = 1)
# Propagation #
#self.grid_propagate(False) # All widgets (the 3 subframes) need to fit in Toplevel window. Minimal window size will be implemented later.
self.Canvas1.grid_propagate(False) # canvas works with scrollbar, widgets dont need to fit in window size.
#self.Frame1.grid_propagate(False) # Frame1 should resize to hold all data (label-widgets)
self.Frame2.grid_propagate(False) # fixed frame dimensions
self.Frame3.grid_propagate(False) # fixed textbox dimensions
self.Frame1.update_idletasks() # just to make sure
### Widgets for the multiple frames ###
# Frame1 - further populated by button command in frame 2#
self.lblaa = Label(self.Frame1, bg="white", text = "Processing...", justify = "left")
self.lblaa.grid(row = 0, column = 0, sticky = N+W)
self.LSlabelsr = []
self.LSlabelsa = []
self.LSlabelsb = []
# Frame 2 #
self.Wbuttontest=Button(self.Frame2, text="Start listing test", command = lambda: refresh(self))
self.Wbuttontest.grid(row = 0, column = 0, columnspan = 3)
self.Wentry = Entry(self.Frame2)
self.Wentry.grid(row = 2, column = 0, columnspan = 3, sticky = E+W, padx = 10)
self.Wentry.delete(0, END)
self.Wentry.insert(0, "user input here")
# Frame3 #
self.Wtext = Text(self.Frame3)
self.Wscrollb = Scrollbar(self.Frame3)
self.Wscrollb.config(command = self.Wtext.yview)
self.Wtext.config(yscrollcommand = self.Wscrollb.set)
self.Wtext.grid(row = 0, column = 0, sticky = N+E+W+S)
### Test-Lists ### Last character in the left column is "ez" !! ###
self.LSa = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
self.LSb = [1, 2, 3, 4, 66, 6, 7, 8, 9, 67, 11, 12, 13, 14, 68]
self.LSr = []
ib = 0
prefix = ""
for i in range(104):
if ib > 25:
prefix = chr(ord("a") + (i/ib - 1))
ib = 0
else:
pass
self.LSr.append(prefix + chr(97+ib))
ib += 1
### FUNCTIONS ###
def resize_frame(self, event):
self.Canvas1.itemconfig(self.CFrame1, width = e.width) #height of frame should depend on the contents.
def scrollevent(event):
self.Canvas1.configure(scrollregion=self.Canvas1.bbox("all"),width=200,height=200)
def refresh(self): ### Button-command: data will be shown ###
if self.lblaa.winfo_exists() == 1:
self.lblaa.destroy()
for i in range(len(self.LSr)):
self.Frame1.rowconfigure(i, weight = 0)
del self.LSlabelsr[:] # remove any previous labels from if the callback was called before
del self.LSlabelsa[:] # remove any previous labels from if the callback was called before
del self.LSlabelsb[:] # remove any previous labels from if the callback was called before
Vlabelheight = 1
# Left List #
for i in range(len(self.LSr)):
self.LSlabelsr.append(Label(self.Frame1, text = str(self.LSr[i]), bg = "LightBlue", justify = "left", height = Vlabelheight))
self.LSlabelsr[i].grid(row = i, column = 0, sticky = E+W)
# Middle List #
for i in range(len(self.LSa)):
self.LSlabelsa.append(Label(self.Frame1, text = str(self.LSa[i]), bg = "LightBlue", fg = "DarkViolet", justify = "left", height = Vlabelheight))
self.LSlabelsa[i].grid(row = i, column = 2, sticky = E+W)
# Right List #
for i in range(len(self.LSb)):
self.LSlabelsb.append(Label(self.Frame1, text = str(self.LSb[i]), bg = "LightBlue", fg = "DarkGreen", justify = "left", height = Vlabelheight))
self.LSlabelsb[i].grid(row = i, column = 4, sticky = E+W)
self.Frame1.update()
self.Frame1.update_idletasks()
print("done")
if __name__ == "__main__":
root = Tk()
root.title("Invisible")
root.resizable(FALSE,FALSE)
root.withdraw()
app = Processing(root)
root.mainloop()
Working version after suggestions by R4PH4EL:
Proper indentation: the functions were defined as part of the init.
Some tweaks on the lambda commands on line 43/107 & 44/110.
from Tkinter import *
import math
class Processing(Toplevel):
def __init__(self, master, *args, **kwargs):
Toplevel.__init__(self, master)
self.master = master
self.title("Process Window")
for r in range(6):
self.rowconfigure(r, weight = 1)
for c in range(4):
self.columnconfigure(c, weight = 1)
### WINDOW size and position definitions ###
ScreenSizeX = master.winfo_screenwidth()
ScreenSizeY = ( master.winfo_screenheight() - 75 ) #about 75pixels for taskbar on bottom of screen (Windows)
ScreenRatio = 0.9
FrameSizeX = int(ScreenSizeX * ScreenRatio)
FrameSizeY = int(ScreenSizeY * ScreenRatio)
FramePosX = (ScreenSizeX - FrameSizeX)/2
FramePosY = (ScreenSizeY - FrameSizeY)/2
self.geometry("%sx%s+%s+%s"%(FrameSizeX,FrameSizeY,FramePosX,FramePosY))
### Creating 3 "sub-frames" ###
# Frame 1 - canvas container with scrollbar#
self.Canvas1 = Canvas(self, bg = "white")
self.Canvas1.grid(row = 0, column = 0, rowspan = 5, columnspan = 4, sticky = N+E+S+W)
self.Canvas1.rowconfigure(1, weight = 1)
self.Canvas1.columnconfigure(1, weight = 1)
self.myscrollbar=Scrollbar(self, orient = "vertical", command = self.Canvas1.yview)
self.Canvas1.configure(yscrollcommand = self.myscrollbar.set)
self.myscrollbar.grid(row = 0, column = 4, rowspan = 5, sticky = N+S)
# Frame 1 - Frame widget in canvas #
self.Frame1 = Frame(self.Canvas1, bg = "white")
self.Frame1.rowconfigure(0, weight = 1)
for c in range(2):
self.Frame1.columnconfigure(1 + (2 * c), weight = 1)#1,3 - columns for small icons in the future
for cb in range(3):
self.Frame1.columnconfigure((cb * 2), weight = 9)#0,2,4 - columns for data
self.CFrame1 = self.Canvas1.create_window(0, 0, window = self.Frame1, width = FrameSizeX, anchor = N+W)
self.Canvas1.bind("<Configure>", lambda event: self.resize_frame(event)) # !!!!! Doesn't work & gives error !!!!!! #
self.Frame1.bind("<Configure>", lambda event: self.scrollevent(event))
self.Canvas1.config(scrollregion=self.Canvas1.bbox("all"))
# Frame 2 #
self.Frame2 = Frame(self, bg= "yellow")
self.Frame2.grid(row = 5, column = 0, rowspan = 1, columnspan = 3, sticky = W+E+N+S)
for r in range(3):
self.Frame2.rowconfigure(r, weight=1)
for c in range(3):
self.Frame2.columnconfigure(c, weight = 1)
# Frame 3 #
self.Frame3 = Frame(self)
self.Frame3.grid(row = 5, column = 3, rowspan = 1, columnspan = 2, sticky = W+E+N+S)
self.Frame3.rowconfigure(0, weight = 1)
self.Frame3.columnconfigure(0, weight = 1)
# Propagation #
#self.grid_propagate(False) # All widgets (the 3 subframes) need to fit in Toplevel window. Minimal window size will be implemented later.
self.Canvas1.grid_propagate(False) # canvas works with scrollbar, widgets dont need to fit in window size.
#self.Frame1.grid_propagate(False) # Frame1 should resize to hold all data (label-widgets)
self.Frame2.grid_propagate(False) # fixed frame dimensions
self.Frame3.grid_propagate(False) # fixed textbox dimensions
self.Frame1.update_idletasks() # just to make sure
### Widgets for the multiple frames ###
# Frame1 - further populated by button command in frame 2#
self.lblaa = Label(self.Frame1, bg="white", text = "Processing...", justify = "left")
self.lblaa.grid(row = 0, column = 0, sticky = N+W)
self.LSlabelsr = []
self.LSlabelsa = []
self.LSlabelsb = []
# Frame 2 #
self.Wbuttontest=Button(self.Frame2, text="Start listing test", command = lambda: self.refresh())
self.Wbuttontest.grid(row = 0, column = 0, columnspan = 3)
self.Wentry = Entry(self.Frame2)
self.Wentry.grid(row = 2, column = 0, columnspan = 3, sticky = E+W, padx = 10)
self.Wentry.delete(0, END)
self.Wentry.insert(0, "user input here")
# Frame3 #
self.Wtext = Text(self.Frame3)
self.Wscrollb = Scrollbar(self.Frame3)
self.Wscrollb.config(command = self.Wtext.yview)
self.Wtext.config(yscrollcommand = self.Wscrollb.set)
self.Wtext.grid(row = 0, column = 0, sticky = N+E+W+S)
### Test-Lists ### Last character in the left column is "ez" !! ###
self.LSa = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
self.LSb = [1, 2, 3, 4, 66, 6, 7, 8, 9, 67, 11, 12, 13, 14, 68]
self.LSr = []
ib = 0
prefix = ""
for i in range(104):
if ib > 25:
prefix = chr(ord("a") + (i/ib - 1))
ib = 0
else:
pass
self.LSr.append(prefix + chr(97+ib))
ib += 1
### FUNCTIONS ###
def resize_frame(self, e):
self.Canvas1.itemconfig(self.CFrame1, width = e.width) #height of frame should depend on the contents.
def scrollevent(self, event):
self.Canvas1.configure(scrollregion=self.Canvas1.bbox("all"),width=200,height=200)
def refresh(self): ### Button-command: data will be shown ###
if self.lblaa.winfo_exists() == 1:
self.lblaa.destroy()
for i in range(len(self.LSr)):
self.Frame1.rowconfigure(i, weight = 0)
del self.LSlabelsr[:] # remove any previous labels from if the callback was called before
del self.LSlabelsa[:] # remove any previous labels from if the callback was called before
del self.LSlabelsb[:] # remove any previous labels from if the callback was called before
Vlabelheight = 1
# Left List #
for i in range(len(self.LSr)):
self.LSlabelsr.append(Label(self.Frame1, text = str(self.LSr[i]), bg = "LightBlue", justify = "left", height = Vlabelheight))
self.LSlabelsr[i].grid(row = i, column = 0, sticky = E+W)
# Middle List #
for i in range(len(self.LSa)):
self.LSlabelsa.append(Label(self.Frame1, text = str(self.LSa[i]), bg = "LightBlue", fg = "DarkViolet", justify = "left", height = Vlabelheight))
self.LSlabelsa[i].grid(row = i, column = 2, sticky = E+W)
# Right List #
for i in range(len(self.LSb)):
self.LSlabelsb.append(Label(self.Frame1, text = str(self.LSb[i]), bg = "LightBlue", fg = "DarkGreen", justify = "left", height = Vlabelheight))
self.LSlabelsb[i].grid(row = i, column = 4, sticky = E+W)
self.Frame1.update()
self.Frame1.update_idletasks()
print("done")
if __name__ == "__main__":
root = Tk()
root.title("Invisible")
root.resizable(FALSE,FALSE)
root.withdraw()
app = Processing(root)
root.mainloop()
Either your indentation is wrong or your getting something wrong in general.
All of your functions are defined inside your __init__ function
Second: if you want to call a class function, you call it by obj.function
Your error on lambda: resize(self) may occur as it should be lambda: self.resize.
Give it a shot with this one and try it.
And please make sure your indentations are correct.
I totally agree with Bryan here - ommiting the lambdas it would be (my personal opinion) easier to read and kind of "better" in a meaning of more structured and pragmatic coding style.
When i put widgets inside my canvas, the widgets bypass the canvas size. But when I scroll, the canvas won't move.
On top of that, the canvas auto re-sizes when I add more widgets. I thought the canvas isn't supposed to re-size because I already added a scroll bar?
Here's my code:
from tkinter import *
from tkinter import ttk
import mysql.connector
class CanvasScroll:
def on_resize(self,event):
self.canvas.config(width = 1185, height = 530)
def add_crew(self):
crewFrame = CrewFrame()
def callback_list(self):
index = self.notebook.index(self.notebook.select()) + 1
self.tmpframe = Try2(self.contentframe, index)
def __init__(self, master):
self.canvas = Canvas(master, width = 1185, height = 530, scrollregion = (0, 0, 1216, 700), bg = 'white', confine = True)
self.canvas.grid(row = 2, column = 0, sticky = 'news')
self.xscroll = ttk.Scrollbar(master, orient = HORIZONTAL, command = self.canvas.xview)
self.xscroll.grid(row = 3, column = 0, sticky = 'we')
self.yscroll = ttk.Scrollbar(master, orient = VERTICAL, command = self.canvas.yview)
self.yscroll.grid(row = 2, column = 1, sticky = 'ns')
self.canvas.config(xscrollcommand = self.xscroll.set, yscrollcommand = self.yscroll.set)
self.canvas.bind("<Configure>", self.on_resize)
self.option = ttk.Frame(master, height = 150, width = 1206)
self.option.grid(row = 0, column = 0, sticky = 'we', columnspan = 5)
self.addicon = PhotoImage(file = 'C:\\Users\\rain\\Desktop\\Fyosh!\\logo\\add.gif').subsample(2,2)
self.btnAdd = ttk.Button(self.option, image = self.addicon, text = 'Add Crew', compound = TOP, command = self.add_crew)
self.btnAdd.grid(row = 0, column = 0, padx = 50, pady = 5)
self.updateicon = PhotoImage(file = 'C:\\Users\\rain\\Desktop\\Fyosh!\\logo\\update.gif').subsample(2,2)
self.btnUpdate = ttk.Button(self.option, image = self.updateicon, text = 'Update Crew', compound = TOP)
self.btnUpdate.grid(row = 0, column = 1, padx = 50)
self.deleteicon = PhotoImage(file = 'C:\\Users\\rain\\Desktop\\Fyosh!\\logo\\delete.gif').subsample(2,2)
self.btnDelete = ttk.Button(self.option, image = self.deleteicon, text = 'Delete Crew', compound = TOP)
self.btnDelete.grid(row = 0, column = 2, padx = 50)
self.reloadicon = PhotoImage(file = 'C:\\Users\\rain\\Desktop\\Fyosh!\\logo\\Refresh.png').subsample(7,7)
self.reloadbtn = ttk.Button(self.option, image = self.reloadicon, command = self.callback_list, text = 'Load List', compound = TOP)
self.reloadbtn.grid(row = 0, column = 3, padx = 50)
self.tabframe = ttk.Frame(master, height = 20)
self.tabframe.grid(row = 1, sticky = 'we')
self.notebook = ttk.Notebook(self.tabframe)
self.notebook.grid(row = 0, column = 0, sticky = 'we')
db = mysql.connector.connect(user = 'root', password = '', host = 'localhost', database = 'fat2x_payroll')
cursor = db.cursor()
ships = ("SELECT * from tbl_shiplist")
try:
cursor.execute(ships)
result = cursor.fetchall()
self.tab = {}
for row in result:
self.tab[row[0]] = {
"shipname": ttk.Frame(self.notebook)
}
self.notebook.add(self.tab[row[0]]["shipname"], text = row[1])
db.close()
except:
messagebox.showinfo("alert", "ship list error")
self.canvas.label = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 0)
self.canvas.label1 = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 1)
self.canvas.label2 = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 2)
self.canvas.label3 = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 3)
self.canvas.label4 = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 4)
self.canvas.label5 = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 5)
self.canvas.label6 = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 6)
self.canvas.label7 = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 7)
self.canvas.label8 = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 8)
def start():
master = Tk()
master.geometry("1206x690+10+10")
master.resizable(0,0)
master.title("Crew Panel")
canvasScroll = CanvasScroll(master)
if __name__ == "__main__":
start()
The canvas can only scroll objects that are embedded on the canvas. In the case of widgets, that means that you've called the create_window method of the canvas for the widgets you want to be affected by the scrollbar.
If you want to use grid to organize widgets, and you want those widgets to be in a scrollable container, the usual method is to put those widgets inside a frame, and then add the frame to the canvas with create_window. You can see an example of this technique in this answer: https://stackoverflow.com/a/3092341/7432
As for the auto-resize, this behavior is completely unrelated to using a scrollbar. If you use grid or pack on a widget, the parent will always resize unless you've turned geometry propagation off. It doesn't matter if it's a Canvas or a Frame or a Toplevel, or any other class of widget.
Basically i've wrote a GUI, to make a maths game and have linked it to my microsft access database using sql, however i cannot get my questions to print to my label, any ideas ?. Also how do you generate a random number from my list of questions, as you can see my jim statement doesnt work.
import Tkinter
import Databaseconnector
class simpleapp_tk(Tkinter.Tk):
def __init__(self,parent):
Tkinter.Tk.__init__(self,parent)
self.parent = parent
self.initialize()
def initialize(self):
jim = randomnumber()
SQL = 'SELECT * FROM tblQuestion'
cursor = Databaseconnector.SELECT(SQL)
rows = cursor.fectchall()
for row in rows:
print row.Question, row.Hint, row.A1, row.A2, row.A3, row.A4, row.CorrectAnswer
alabel2.set("Question: " + (row.question)(jim).Item(1))
def create_widgets(self):
# create welcome label
label1 = Tkinter.Label(self, text = "Question Game !")
label1.grid(row = 0, column = 1, columnspan = 2, sticky = 'W')
# create intruction label
alabel2 = Tkinter.Label(self, text = "")
alabel2.grid(row = 1, column = 0, columnspan = 2, sticky = 'W')
a1loginbutton = Tkinter.Button(self, text = "Enter",)
a1loginbutton.grid(row = 9, column = 1, sticky = 'W')
label3 = Tkinter.Label(self, text = "")
label3.grid(row = 10, column = 0, columnspan = 2, sticky = 'W')
a2loginbutton = Tkinter.Button(self, text = "Enter",)
a2loginbutton.grid(row = 11, column = 1, sticky = 'W')
a3loginbutton = Tkinter.Button(self, text = "Enter",)
a3loginbutton.grid(row = 9, column = 3, sticky = 'E')
a4loginbutton = Tkinter.Button(self, text = "Enter",)
a4loginbutton.grid(row = 11, column = 3, sticky = 'E')
label4 = Tkinter.Label(self, text = "")
label4.grid(row = 12, column = 0, columnspan = 2, sticky = 'W')
hiloginbutton = Tkinter.Button(self, text = "Hint",)
hiloginbutton.grid(row = 13, column = 3, sticky = 'E')
label5 = Tkinter.Label(self, text = "Score:")
label5.grid(row = 14, column = 1, columnspan = 5, sticky = 's')
def close_page(self):
self.destroy()
if __name__ == "__main__":
app = simpleapp_tk(None)
app.title('my application')
app.geometry("150x200")
app.mainloop()
Edited based on comments from OP:
There is a typo in this line: rows = cursor.fectchall()
Try changing the label.set statement to a simple case to confirm that this works. alabel2.set("Question: " + row.question)
What is the randomnumber() function, and what is the (row.question)(jim).Item(1) line supposed to return?