Home > database >  Is there a way to have the date entry calendar show up in a blank Date Entry field? (Tkcalendar)
Is there a way to have the date entry calendar show up in a blank Date Entry field? (Tkcalendar)

Time:05-04

I'm using the latest version of Tkcalendar. Whenever the date entry field is blank, the dropdown doesn't pop up. It throws this error:

Traceback (most recent call last):
  File "C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python39_64\lib\tkinter\__init__.py", line 1892, in __call__
    return self.func(*args)
  File "C:\Users\JEvans\AppData\Roaming\Python\Python39\site-packages\tkcalendar\dateentry.py", line 246, in _on_b1_press
    self.drop_down()
  File "C:\Users\JEvans\AppData\Roaming\Python\Python39\site-packages\tkcalendar\dateentry.py", line 331, in drop_down
    date = self.parse_date(self.get())
  File "C:\Users\JEvans\AppData\Roaming\Python\Python39\site-packages\tkcalendar\calendar_.py", line 1223, in parse_date
    year = numbers[indexes['Y']]
IndexError: list index out of range

Here's how the date entry widget is constructed in the program:

from tkinter import *
from tkinter import ttk

from tkcalendar import *
import tkcalendar


window = Tk()

class DateEntry(tkcalendar.DateEntry):
    def _validate_date(self):
        if not self.get():
            return True # IMPORTANT!!! Validation must return True/False otherwise it is turned off by tkinter engine
        
        return super()._validate_date()


def test():
    pass

window.geometry('500x500')

dob = DateEntry(window, date_pattern = 'mm/dd/yyyy', width = 15, background= 'gray61', foreground="white", locale='en_US')
dob.place(x = 125, y =125)
dob.bind("<<DateEntrySelected>>", test)

dob2 = DateEntry(window, date_pattern = 'mm/dd/yyyy', width = 15, background= 'gray61', foreground="white", locale='en_US')
dob2.place(x =200, y =200)
dob2.bind("<<DateEntrySelected>>", test)


window.mainloop()

Here is what happens when I click the dropdown. Nothing appears and it returns the error message above.

This is what happens when the dropdown is clicked. It just freezes and returns the error message.

Is there anyway to bypass this error and have the dropdown show without entering a date value?

Extra Clarification: The date entry works perfectly when there is a date in the date entry field. The error only appears when the field is blank.

CodePudding user response:

Problem is that dropdown needs value from this entry to generate window with calendar.

It seems normally it replaces empty string in entry with current date and later dropdown gets this current date from entry.

Your code stops replacing empty string so it makes problem with rest of code.

Error shows that parse_date() makes problem when you have empty string - so it would need to replace this method and also check if text is empty and use some correct date (ie. current date) so dropdown will know what to generate in window with calendar.

I checked source code (using path from tkcalendar.__file__) and it seems DateEntry doesn't have this function but in __init__ it sets self.parse_date = self._calendar.parse_date and it need different method to replace it.

It needs to run original __init__ and later keep previous self.paser_date and assign own function to self.parse_date.

Full working code

import tkinter as tk   # PEP8: `import *` is not preferred
from tkinter import ttk
import tkcalendar
import datetime

#print(tkcalendar.__file__) path to source code (skip __init__.py)

# --- classes ---

class DateEntry(tkcalendar.DateEntry):
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        
        self.old_parse_date = self.parse_date
        
        self.parse_date = self.new_parse_date
        
    def _validate_date(self):
        if not self.get():
            return True
        
        return super()._validate_date()

    def new_parse_date(self, text):
        print(f'parse_date: >{text}<')

        if not text:
            return datetime.datetime.now()   # return some default date

        return self.old_parse_date(text)     # runs original function
    
# --- functions ---

def test(event):
    print('test:', event)

# --- main ---

window = tk.Tk()

tk.Label(window, text='tkcalendar.DateEntry').pack(padx=5, pady=5)

dob1 = tkcalendar.DateEntry(window, date_pattern='mm/dd/yyyy', locale='en_US')
dob1.pack()
dob1.bind("<<DateEntrySelected>>", test)

tk.Label(window, text='My DateEntry').pack(padx=5, pady=5)

dob2 = DateEntry(window, date_pattern = 'mm/dd/yyyy', locale='en_US')
dob2.pack()
dob2.bind("<<DateEntrySelected>>", test)

window.mainloop()
  • Related