it's a code for a Calendar, recording the subjects for a specific day.
I want it to open a dropdown list of the subject list when the day is clicked. And when multiple subjects are selected, I want the selected strings to be displayed a little under the button that was clicked, on the screen.
PROBLEM, This is the code so far, I can’t accustom it to open the list, just under the specific button clicked. it opens in the center, I want it to open just under the specific button that is clicked. (I don't use an Optionbox because I want to select multiple items at once and it's not quite going well.)
import tkinter as tk
from tkinter import ttk
from tkinter import *
from PIL import ImageTk, Image
screen = tk.Tk()
screen.geometry("1423x817")
title = screen.title("Class Calendar")
# SCROLL BAR
# main frame that holds everything.
main_frame = Frame(screen, bg = 'blue')
main_frame.pack(fill = BOTH, expand = 1)
# CANVAS THAT IS SCROLLED
Canvasheight, Canvaswidth = 817, 1408
canvas = Canvas(main_frame, height = Canvasheight, width = Canvaswidth, borderwidth=0,
highlightthickness =0, relief = 'flat', highlightcolor="white", highlightbackground= 'white')
canvas.config(bg = '#a1d0ea')
canvas.pack(side = LEFT, fill= BOTH, expand = 1)
# ADDING SCROLLBAR TO CANVAS
scroll_bar = ttk.Scrollbar( main_frame, orient=VERTICAL, command = canvas.yview)
scroll_bar.pack(side = RIGHT, fill= Y)
# BIND TO MOUSE SCROLLING, CONFIGURING
canvas.configure(yscrollcommand=scroll_bar.set)
canvas.bind('<Configure>', lambda e: canvas.configure(scrollregion=canvas.bbox("all")))
# A FRAME TO HOLD THINGS ON THE CANVAS
second_frame = Frame(main_frame, height = Canvasheight*8, width = Canvaswidth 5, borderwidth=0, highlightthickness =0, relief= 'flat', highlightcolor="white", highlightbackground='white')
second_frame.config(bg = '#a1d0ea')
canvas.create_window((0,0), window = second_frame, anchor='nw', width= Canvaswidth) # 'w' near middle lower half in scroll bar
# BACKGROUND PICTURE
img1 = ImageTk.PhotoImage(Image.open("Screenshot 2022-06-28 at 10.29.24 AM.png"))
label1 = Label(second_frame, image = img1, borderwidth=0, highlightthickness =0, relief= 'flat', highlightcolor="white", highlightbackground="white")
label1.config( bg = '#a1d0ea')
label1.pack()
img2 = ImageTk.PhotoImage(Image.open("Screenshot 2022-06-28 at 10.29.24 AM.png"))
label2 = Label(second_frame, image = img2, borderwidth=0, highlightthickness =0, relief= 'flat', highlightcolor="white", highlightbackground="white")
label2.config(bg = '#a1d0ea')
label2.pack()
# A SIDE MENUE
def toggle_win():
bg1 = ("#262626")
f3 = Frame(second_frame, width = 340, height = 817, bg = bg1)
f3.place(x = 0, y =0)
def dele():
f3.destroy()
menubtnclose = Button(f3, text = 'X', command = dele, border = 0, activebackground = '#12c4c0', borderwidth=0, highlightthickness =0).place(x = 5, y = 10)
anotherbtn = Button(second_frame, command = toggle_win, text = '=', font = (39), borderwidth=0, highlightthickness =0, bg = '#9ad0f0', highlightbackground='#9ad0f0', highlightcolor='#9ad0f0').place(x= 5, y = 10)
###################################################################
# THE OPTIONS LIST BOX
def optionbox():
#frame for list
global f4
f4 = Frame(second_frame, width = 200, height = 270, border = 1)
f4.place(x = 570, y = 260)
# func for closing
def delet():
def select():
var = StringVar
subject = []
sname = list2.curselection()
for i in sname:
op = list2.get(i)
subject.append(op)
for i in subject:
Label(second_frame, text = subject, borderwidth=0, highlightthickness =0, relief="flat", highlightcolor="white").place(x = newx, y = newy)
select()
f4.destroy()
fclose = Button(f4, text = 'X', command = delet, border = 0, activebackground = '#12c4c0', borderwidth=0, highlightthickness =0).place(x = 1, y = 1)
#listbox
global clicked
global sublist
clicked = StringVar()
global list2
list2 = Listbox(f4, font = ("arial", 20), width = 16, height = 9, selectborderwidth=1, selectmode=MULTIPLE)
list2.place(x = 0, y = 26)
# list
sublist = ["Biology", "Physics", "chemistry", "Science", "Sinhala"]
#insert items
for item in sublist:
list2.insert(0, item)
###############################################################
# CALENDAR
# PRINTING MARCH TO WINDOW
march22_label = Label(second_frame, text = "MARCH", font = ("arial", 27),fg='black', borderwidth=0, highlightthickness =0)
march22_label.config(bg = '#9ad0f0')
march22_label.place( x= 664, y = 18)
# PRINTING WEEK TO WINDOW
marchweek22_label = Label(second_frame, text =
"""
Monday Tuesday Wednesday Thursday Friday Saturday Sunday
""",
font= ('arial', 25),fg='black', borderwidth=0, highlightthickness =0)
marchweek22_label.config(bg = '#a1d0ea')
marchweek22_label.place(x= 100, y = 82)
def March22():
i = 1
global newy
global newx
x, y = 310, 194
while i < 7:
newx, newy = x, y 30
Button(second_frame, text = i, font = ("arial", 25), borderwidth=0, highlightthickness =0, command = optionbox).place(x = x, y = y)
x = x 185
i = i 1
x, y = 125, y 130
while i < 14:
newx, newy = x, y 30
Button(second_frame, text = i, font = ("arial", 25), borderwidth=0, highlightthickness =0, command = optionbox).place(x = x, y = y)
x = x 185
i = i 1
x, y = 125, y 130
while i < 21:
newx, newy = x, y 30
Button(second_frame, text = i, font = ("arial", 25),borderwidth=0, highlightthickness =0, command = optionbox).place(x = x, y = y)
x = x 185
i = i 1
x, y = 125, y 130
while i < 28:
newx, newy = x, y 30
Button(second_frame, text = i, font = ('arial', 25),borderwidth=0, highlightthickness =0, command = optionbox).place(x = x, y = y)
x = x 185
i = i 1
x, y = 125, y 130
while i < 32:
newx, newy = x, y 30
Button(second_frame, text = i, font = ("arial", 25),borderwidth=0, highlightthickness =0, command = optionbox).place(x = x, y = y)
x = x 185
i = i 1
March22()
screen.mainloop()
PROBLEM, And when another button is clicked, without closing the previous list. it seems to just open on it and not open a completely different list, so it gets stuck and the Destroy command doesn't work.
PROBLEM, And about displaying the selected subjects, I want it to be displayed under the specific button that was clicked, but I can't get that to work.
I’m quite new to python and Tkinter. I have tried a few ways to make it work, but I am not finding any successful results. Please help me in writing it. Please ask if I anything is unclear.
CodePudding user response:
Instead of using a function to make the option box, it would be better to use a class which subclasses Frame
.
class OptionBox(Frame):
def __init__(self, master, parent_x, parent_y):
# Initialise frame and place it
Frame.__init__(self, master, width = 200, height = 270, border = 1)
self.place(x=parent_x, y=parent_y)
# Store position of parent
self.parent_x = parent_x
self.parent_y = parent_y
fclose = Button(self, text = 'X', command = self.delete, border = 0, activebackground = '#12c4c0', borderwidth=0, highlightthickness =0).place(x = 1, y = 1)
self.clicked = StringVar()
self.list2 = Listbox(self, font = ("arial", 20), width = 16, height = 9, selectborderwidth=1, selectmode=MULTIPLE)
self.list2.place(x = 0, y = 26)
# list
self.sublist = ["Biology", "Physics", "chemistry", "Science", "Sinhala"]
#insert items
for item in self.sublist:
self.list2.insert(0, item)
def delete(self):
self.select()
self.destroy()
def select(self):
var = StringVar()
subject = []
sname = self.list2.curselection()
for i in sname:
op = self.list2.get(i)
subject.append(op)
for n, i in enumerate(subject):
Label(second_frame, text = i, borderwidth=0, highlightthickness =0, relief="flat", highlightcolor="white").place(x = self.parent_x, y = self.parent_y (n*20))
This is similar to what you had before, but can be created multiple times without breaking the others. If you haven't seen classes before, research object oriented programming in python. This class uses the position of it's parent (the button which was clicked) to work out where to place itself and the subject labels.
There is also a simpler way to create the buttons for each day.
def March22():
x, y = 310, 194
# For each day in the month
for i in range(1, 32):
# Create a button
b = Button(second_frame, text = i, font = ("arial", 25), borderwidth=0, highlightthickness =0)
# Place it
b.place(x = x, y = y)
# Update the frame so we can get the height/width of the button
second_frame.update_idletasks()
# Create the option box command, increasing y by the height of the button so it is below it.
b.config(command = lambda x=x, y=y b.winfo_height(): OptionBox(second_frame, x, y))
x = 185 # Increase x by 185 for every 1 across
# Start a new line every time i is 1 less than a multiple of 7
if i % 7 == 6:
x = 125 # Reset x
y = 130 # Increase y
Instead of using multiple while
loops you can refactor it into a single for
loop. The button command creates a new instance of OptionBox
relative to the position of the button.