Malina
Malina

Reputation: 13

Tkcalendar DateEntry - Allow Widget to Return No Selection as Blank

I have created a GUI where the user can select a date from a drop down using the tkcalendar DateEntry widget. I would like to allow the user the option of not selecting a date and leaving this widget blank. However, even if no date is selected the widget returns the current date.

Is there a way to configure the DateEntry to allow for no selection rather than defaulting to the current date if the user does not select a date?

Below is a subset of my code:

import pandas as pd
from tkinter import *
from tkinter.ttk import *
import tkinter as tk
from tkcalendar import DateEntry  

class Window(Frame):
    def __init__(self, master):
        Frame.__init__(self,master)
        master.title('Solar Master Project Tracking')

        # create canvas for scrollable window
        canvas = Canvas(root)
        canvas.grid(row=1,column=0, columnspan=2)

        # create vertical scrollbar and connect it to the canvas
        scrollBar = tk.Scrollbar(root, orient='vertical', command = canvas.yview)
        scrollBar.grid(row=1, column=2, sticky = 'ns')
        canvas.configure(yscrollcommand=scrollBar.set)

        def update_scroll_region(event):
            canvas.configure(scrollregion=canvas.bbox("all"))

        def _on_mousewheel(event):
            canvas.yview_scroll(int(-1*(event.delta/120)), "units")

        # create a frame for the widgets in the scrollable canvas
        scroll_frame = Frame(canvas)
        scroll_frame.bind("<Configure>", update_scroll_region)
        canvas.create_window(0,0, anchor='nw', window = scroll_frame)
        canvas.bind_all("<MouseWheel>", _on_mousewheel)

        # Proposal Date
        self.L18 = Label(scroll_frame, text="Proposal Date:",font=('TKDefaultFont', 8, 'bold'))
        self.L18.grid(row=21, column=0, sticky=W)
        self.prop_date_selection = DateEntry(scroll_frame, width = 25, background = 'LightCyan3',
                                             foreground ='white',borderwidth=2)
        self.prop_date_selection.grid(row=21, column=1,sticky=E)
        self.prop_date_selection.delete(0,"end")


        # SUBMIT INFORMATION
        self.button = tk.Button(root, text="Insert / Update Project",font=('TKDefaultFont', 10, 'bold'),
                                relief=RAISED, command = self.store_user_inputs, bg = "gray80")
        self.button.grid(row=25, column = 0, columnspan=8, sticky = 'EW')

    # STORE USER INPUT
    def store_user_inputs(self):
        prop_date_selection = self.prop_date_selection.get_date()

        global params
        params = [prop_date_selection]
        root.destroy()

if __name__ == "__main__":
    root = Tk()
    Window(root)
    root.mainloop()  

Upvotes: 1

Views: 1537

Answers (3)

jmab-2000
jmab-2000

Reputation: 11

I was facing the same issue, and I resolved by modifying _validate_date() and drop_down() function

I first try to _set_text the input to empty string

tk.Label(parent, text="Time Range (Start):").grid(row=4, column=0, sticky='w')
self.start_time = MyDateEntry(parent, width=12, background='darkblue', foreground='white', borderwidth=2)
self.start_time._set_text('')

Then I manage to create a simple date checking to allow drop down to be displayed

Here is MyDateEntry class looks like

class MyDateEntry(tkcalendar.DateEntry):

    def drop_down(self):
        """Display or withdraw the drop-down calendar depending on its current state."""
        if self._calendar.winfo_ismapped():
            self._top_cal.withdraw()
        else:
            self._validate_date()
            # CHANGES: Default to date today when drop down is selected
            date = datetime.datetime.now().strftime("%m/%d/%Y")
            if self.get() != '':
                date = self.parse_date(self.get())

            x = self.winfo_rootx()
            y = self.winfo_rooty() + self.winfo_height()
            if self.winfo_toplevel().attributes('-topmost'):
                self._top_cal.attributes('-topmost', True)
            else:
                self._top_cal.attributes('-topmost', False)
            self._top_cal.geometry('+%i+%i' % (x, y))
            self._top_cal.deiconify()
            self._calendar.focus_set()
            self._calendar.selection_set(date)


    def _validate_date(self):
        if self.get() == '':
            return True # Modified from Roman's Answer
        
        return super()._validate_date()

It was encountering error on drop down when the validated empty date was selected

Upvotes: 1

Roman
Roman

Reputation: 35

For those who find this post.

Modifying get_date() didn't change anything in my case. But the following did:

class MyDateEntry(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()

Upvotes: 0

j_4321
j_4321

Reputation: 16179

You can create a class inheriting from tkcalendar.DateEntry and modify the get_date() method to return None when the DateEntry is empty:

import tkcalendar

class DateEntry(tkcalendar.DateEntry):
    def get_date(self):
        if not self.get():
            return None
        self._validate_date()
        return self.parse_date(self.get())

Upvotes: 0

Related Questions