0

I developed this code to use it as a calendar, and at the end, it return the date on a specific format.

from tkinter import*
from tkinter import ttk
from PyQt5.QtCore import QDate, Qt

class Calendar:

def __init__(self):
    self.b = 0

def calendar(self):

    calendar_window = Tk()
    calendar_window.title("Calendar")
    calendar_window.geometry("180x300")
    calendar_window.resizable(False,False)

    Label(calendar_window, text = "DATE") .place(x = 70, y =0)

    Label(calendar_window, text = "Month") .place(x = 30, y = 20)
    month = StringVar()
    month = ttk.Combobox(calendar_window, width = 5, textvariable = month , 
state = "readonly")
    month.place(x = 30, y = 40) 
    month['values'] = ['JAN' ,'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 
'AGU', 'SEP', 'OCT', 'NOV', 'DEC']

    Label(calendar_window, text = "Year") .place(x = 110, y = 20)
    year = StringVar()
    year = ttk.Combobox(calendar_window, width = 5, textvariable = year , 
state = "readonly")
    year.place(x = 110, y = 40) 
    year["values"] = ["2015" ,"2016", "2017", "2018", "2019", "2020", 
"2021", "2022"]
    year.current(0)

    day = StringVar()
    day_list = []

    def radiobutton_creation(event):
        days = Frame(calendar_window, width = 180, height = 150) 
        days.place(x = 3, y = 70)
        if month.current() != -1:
            d = QDate(int(year.get()), month.current() + 1, 1)
            x = [5,30,55,80,105,130,155]
            y = [5,35,65,95,125]
            i = 1
            for ver in y:
                for hor in x:
                    if i <= int(d.daysInMonth()): 
                        b = Radiobutton(days, text = 
str(i),variable=day,value= str(i), height = 1, width = 1,indicatoron=0) 
                        b.place(x = hor, y = ver)
                        day_list.append(b)
                        i = i + 1

    month.bind('<<ComboboxSelected>>', radiobutton_creation)
    year.bind('<<ComboboxSelected>>', radiobutton_creation)

    Label(calendar_window, text = "HH") .place(x = 55, y =220)
    hh = StringVar()
    hh = ttk.Combobox(calendar_window, width = 3, textvariable = hh,state = 
"readonly")
    hh.place(x = 55, y = 240) 
    hh["values"] = ["00","01" ,"02", "03", "04", "05", "06", "07", "08", 
"09", "10","11","12","13","14","15","16","17","18","19","20","21","22","23"]
    Label(calendar_window, text = "MM") .place(x = 100, y =220)
    mm = StringVar()
    mm = ttk.Combobox(calendar_window, width = 3, textvariable = mm,state = 
"readonly")
    mm.place(x = 100, y = 240) 
    mm["values"] = ["00","01" ,"02", "03", "04", "05", "06", "07", "08", 
 "09","10","11","12","13","14","15","16",
 "17","18","19","20","21","22","23","24","25"
,"26","27","28","29","30","31","32","33","34"
,"35","36","37","38","39","39","40","42","43"
,"44","45","46","47","48","49","50","51","52"
,"53","54","55","56","57","58","59"]
    Label(calendar_window, text = "Z") .place(x = 145, y =240)

    def select():
        if len(day.get()) < 2:
            self.b = 
('0'+day.get()+hh.get()+mm.get()+"Z"+month.get()+year.get())
            calendar_window.destroy()
        else:
            self.b = 
(day.get()+hh.get()+mm.get()+"Z"+month.get()+year.get())
            calendar_window.destroy()

    Button(calendar_window, text = "Select", command = select) .place(x = 
30, y = 270)
    Button(calendar_window, text = "Cancel", command = 
calendar_window.destroy) .place(x = 90, y = 270)


    calendar_window.update()


    calendar_window.mainloop()

    return returns()

It works fine, even if a create a new .py file and I code:

from calendar_class import Calendar
print(Calendar().calendar())

Nevertheless when I try to use this with a Label in Tkinter, it doesn`t work:

from tkinter import*
from tkinter import ttk
from calendar_class import Calendar

master = Tk()
master.title("ATO (Air Tasking Order)")
master.geometry('500x500')
def execute():
 date = StringVar()
 date.set(Calendar().calendar())
 Label(master, textvariable = date) .grid(row = 1, column = 1)
Button(master, text = 'Show Date', command = execute) .grid(row = 2, column 
= 2)
mainloop()

Or just trying to use print inside a ttk() window it works after the window is closed:

from tkinter import*
from tkinter import ttk
from calendar_class import Calendar


master = Tk()
master.title("ATO (Air Tasking Order)")
master.geometry('500x500')
print(Calendar().calendar())
mainloop()
Andres
  • 59
  • 2
  • 11

1 Answers1

1

The issue here is the call to mainloop in calendar class method. When you call mainloop function, your code gets stuck there waiting for user events on you GUI. It can only go to next line of code when quit is called on it, which in your case is called when you close the window.

I would suggest to use calendar_window.update() in your class method, which will draw your window but will not block your code there. Don't remove the mainloop call from your main function, otherwise the code will not wait for any user input and end execution instantly.

Refer to this answer for more details about working of mainloop.

UPDATE:

Sorry, I did not try to run your code last time. Assuming you are returning the selected date from Calendar class, these changes in Calendar class can solve your problem.

def select():
    if len(day.get()) < 2:
        self.b = ('0'+day.get()+hh.get()+mm.get()+"Z"+month.get()+year.get())
        calendar_window.quit()
    else:
        self.b = (day.get()+hh.get()+mm.get()+"Z"+month.get()+year.get())
        calendar_window.quit()

Button(calendar_window, text = "Select", command = select) .place(x = 30, y = 270)
Button(calendar_window, text = "Cancel", command = calendar_window.quit) .place(x = 90, y = 270)

calendar_window.mainloop()
calendar_window.destroy()

return self.b

So when you call the quit on button click, it will call destroy and then go to next call of return. And you can use your main function as showed in the question and it will work.

And why directly calling destroy on button click is not working (I guess) is related to use of two Tk() windows in same application(not suggested). So I would suggest to pass your master window as argument to Calendar class and then create Toplevel window instead of new Tk() window there. You can read more about Toplevel window here.

Hope this solves your problem finally.

Kamal
  • 2,384
  • 1
  • 13
  • 25
  • Please accept the answer if it solved your problem..:-) https://stackoverflow.com/help/someone-answers – Kamal Nov 02 '18 at 06:23
  • I try using the update and still using the mainloop as you told me, but this is not working, at the end is the same. I am doing a deep research about the topic to understand it better, thanks – Andres Nov 05 '18 at 12:43
  • Please update the exact code you tried, and I can try that at my end. – Kamal Nov 06 '18 at 01:31
  • I already update it, I am not even sure about where to locate the .update(). I put it at the end of the code, just before the mainloop(). I am not sure if it is right, but it is clearly not working – Andres Nov 07 '18 at 03:28
  • I already update it, I am not even sure about where to locate the .update(). I put it at the end of the code, just before the mainloop(). I am not sure if it is right, but it is clearly not working – Andres Nov 07 '18 at 03:28
  • I tried your code, In the Calendar class last call is `return returns()`, but I can't see the definition of function `returns` anywhere. – Kamal Nov 08 '18 at 05:02
  • I am sorry In just checked your updated answer, using top level is the kwy to solve the problem, you are correct, thank you again – Andres Nov 15 '18 at 02:15