From 08e11e860cf9caae156f70e709fa665d48393333 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Mon, 30 Mar 2020 09:56:42 -0400 Subject: [PATCH] Integrated new date chooser!! (FINALLY) --- PySimpleGUI.py | 135 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 92 insertions(+), 43 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index a9602f98..e64e1846 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.18.0.4 Unreleased - Print and MLine.Print fixed sep char handling, popup_get_date, icon parm popup_animated, popup button size (6,1)" +version = __version__ = "4.18.0.5 Unreleased - Print and MLine.Print fixed sep char handling, popup_get_date, icon parm popup_animated, popup button size (6,1), NEW CALENDAR chooser integrated" port = 'PySimpleGUI' @@ -118,6 +118,7 @@ import datetime import time import pickle import calendar +import datetime import textwrap import inspect # from typing import List, Any, Union, Tuple, Dict # because this code has to run on 2.7 can't use real type hints. Must do typing only in comments @@ -128,7 +129,6 @@ from math import fabs from functools import wraps from subprocess import run, PIPE from threading import Thread -import calendar as cal import itertools import os @@ -2787,6 +2787,11 @@ class Button(Element): self.TKCal = None self.CalendarCloseWhenChosen = None self.CalendarDefaultDate_M_D_Y = (None, None, None) + self.CalendarCloseWhenChosen = False + self.CalendarLocale = None + self.CalendarFormat = None + self.CalendarNoTitlebar = True + self.CalendarBeginAtSundayPlus = 0 self.InitialFolder = initial_folder self.Disabled = disabled self.ChangeSubmits = change_submits or enable_events @@ -2937,37 +2942,48 @@ class Button(Element): Window._DecrementOpenCount() elif self.BType == BUTTON_TYPE_CALENDAR_CHOOSER: # this is a return type button so GET RESULTS and destroy window # ------------ new chooser code ------------- - # - # if self.CalendarDefaultDate_M_D_Y == (None, None, None): - # now = datetime.datetime.now() - # cur_month, cur_day, cur_year = now.month, now.day, now.year - # else: - # cur_month, cur_day, cur_year = self.CalendarDefaultDate_M_D_Y - # - # date_chosen = popup_get_date(start_mon=cur_month, start_day=cur_day, start_year=cur_year, close_when_chosen=self.CalendarCloseWhenChosen) - # - # strvar.set(date_chosen) - # self.TKStringVar.set(date_chosen) + + if self.CalendarDefaultDate_M_D_Y == (None, None, None): + now = datetime.datetime.now() + cur_month, cur_day, cur_year = now.month, now.day, now.year + else: + cur_month, cur_day, cur_year = self.CalendarDefaultDate_M_D_Y + + date_chosen = popup_get_date(start_mon=cur_month, start_day=cur_day, start_year=cur_year, close_when_chosen=self.CalendarCloseWhenChosen, no_titlebar=self.CalendarNoTitlebar, begin_at_sunday_plus=self.CalendarBeginAtSundayPlus, locale=self.CalendarLocale) + if date_chosen is not None: + month, day, year = date_chosen + now = datetime.datetime.now() + hour, minute, second = now.hour, now.minute, now.second + try: + date_string = calendar.datetime.datetime(year, month, day, hour, minute, second).strftime(self.CalendarFormat) + except Exception as e: + print('Bad format string', e) + date_string = 'Bad format string' + + target_element.update(date_string) + + strvar.set(date_string) + self.TKStringVar.set(date_string) # ------------ old chooser code ------------- - should_submit_window = False - root = tk.Toplevel() - root.title('Calendar Chooser') - root.wm_attributes("-topmost", 1) - self.TKCal = TKCalendar(master=root, firstweekday=calendar.SUNDAY, target_element=target_element, - close_when_chosen=self.CalendarCloseWhenChosen, default_date=self.CalendarDefaultDate_M_D_Y, - locale=self.CalendarLocale, format=self.CalendarFormat) - self.TKCal.pack(expand=1, fill='both') - root.update() - - if type(Window._user_defined_icon) is bytes: - calendar_icon = tkinter.PhotoImage(data=Window._user_defined_icon) - else: - calendar_icon = tkinter.PhotoImage(data=DEFAULT_BASE64_ICON) - try: - root.tk.call('wm', 'iconphoto', root._w, calendar_icon) - except: - pass + # should_submit_window = False + # root = tk.Toplevel() + # root.title('Calendar Chooser') + # root.wm_attributes("-topmost", 1) + # self.TKCal = TKCalendar(master=root, firstweekday=calendar.SUNDAY, target_element=target_element, + # close_when_chosen=self.CalendarCloseWhenChosen, default_date=self.CalendarDefaultDate_M_D_Y, + # locale=self.CalendarLocale, format=self.CalendarFormat) + # self.TKCal.pack(expand=1, fill='both') + # root.update() + # + # if type(Window._user_defined_icon) is bytes: + # calendar_icon = tkinter.PhotoImage(data=Window._user_defined_icon) + # else: + # calendar_icon = tkinter.PhotoImage(data=DEFAULT_BASE64_ICON) + # try: + # root.tk.call('wm', 'iconphoto', root._w, calendar_icon) + # except: + # pass elif self.BType == BUTTON_TYPE_SHOW_DEBUGGER: if self.ParentForm.DebuggerEnabled: _Debugger.debugger._build_floating_window() @@ -8925,21 +8941,30 @@ def CalendarButton(button_text, target=(None, None), close_when_date_chosen=True image_filename=None, image_data=None, image_size=(None, None), image_subsample=None, tooltip=None, border_width=None, size=(None, None), auto_size_button=None, button_color=None, disabled=False, font=None, bind_return_key=False, focus=False, pad=None, - key=None, locale=None, format=None, metadata=None): + key=None, locale=None, format='%Y-%m-%d %H:%M:%S', begin_at_sunday_plus=0, no_titlebar=True, metadata=None): """ + Button that will show a calendar chooser window. Fills in the target element with result :param button_text: text in the button :type button_text: (str) - :param target: + :param target: Key or "coordinate" (see docs) of target element + :type target: Union[(int, int), Any] :param close_when_date_chosen: (Default = True) - :param default_date_m_d_y: (Default = (None)) + :type close_when_date_chosen: bool + :param default_date_m_d_y: Beginning date to show + :type default_date_m_d_y: (int, int or None, int) :param image_filename: image filename if there is a button image + :type image_filename: image filename if there is a button image :param image_data: in-RAM image to be displayed on button + :type image_data: in-RAM image to be displayed on button :param image_size: (Default = (None)) - :param image_subsample:amount to reduce the size of the image + :type image_size: (Default = (None)) + :param image_subsample: amount to reduce the size of the image + :type image_subsample: amount to reduce the size of the image :param tooltip: text, that will appear when mouse hovers over the element :type tooltip: (str) :param border_width: width of border around element + :type border_width: width of border around element :param size: (w,h) w=characters-wide, h=rows-high :type size: Tuple[int, int] :param auto_size_button: True if button size is determined by button text @@ -8951,13 +8976,21 @@ def CalendarButton(button_text, target=(None, None), close_when_date_chosen=True :param font: specifies the font family, size, etc :type font: Union[str, Tuple[str, int]] :param bind_return_key: (Default = False) + :type bind_return_key: bool :param focus: if focus should be set to this + :type focus: bool :param pad: Amount of padding to put around element in pixels (left/right, top/bottom) :type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int) :param key: key for uniquely identify this element (for window.FindElement) :type key: Union[str, int, tuple] - :param locale: - :param format: + :param locale: defines the locale used to get day names + :type locale: str + :param format: formats result using this strftime format + :type format: str + :param no_titlebar: if True no titlebar will be shown on the date chooser window + :type no_titlebar: bool + :param metadata: Anything you want to store along with this button + :type metadata: Any :return: returns a button :rtype: (Button) """ @@ -8970,6 +9003,8 @@ def CalendarButton(button_text, target=(None, None), close_when_date_chosen=True button.CalendarDefaultDate_M_D_Y = default_date_m_d_y button.CalendarLocale = locale button.CalendarFormat = format + button.CalendarNoTitlebar = no_titlebar + button.CalendarBeginAtSundayPlus = begin_at_sunday_plus return button @@ -14247,20 +14282,22 @@ def PopupGetText(message, title=None, default_text='', password_char='', size=(N -def popup_get_date(start_mon, start_day, start_year, begin_at_sunday_plus=0, no_titlebar=True, keep_on_top=True, location=(None, None), close_when_chosen=False, icon=None): +def popup_get_date(start_mon, start_day, start_year, begin_at_sunday_plus=0, no_titlebar=True, keep_on_top=True, location=(None, None), close_when_chosen=False, icon=None, locale=None): """ Display a calendar window, get the user's choice, return as a tuple (mon, day, year) :param start_mon: The starting month :type start_mon: int :param start_day: The starting day - optional. Set to 0 if no date to be chosen at start - :type start_day: int + :type start_day: int or None :param start_year: The starting year :type start_year: int :param begin_at_sunday_plus: Determines the left-most day in the display. 0=sunday, 1=monday, etc :type begin_at_sunday_plus: int :param icon: Same as Window icon parameter. Can be either a filename or Base64 value. For Windows if filename, it MUST be ICO format. For Linux, must NOT be ICO :type icon: str + :param locale: locale used to get the day names + :type locale: str :return: Tuple containing (month, day, year) of chosen date or None if was cancelled :rtype: None or (int, int, int) """ @@ -14271,7 +14308,7 @@ def popup_get_date(start_mon, start_day, start_year, begin_at_sunday_plus=0, no def update_days(window, month, year, begin_at_sunday_plus): [window[(week, day)].update('') for day in range(7) for week in range(6)] - weeks = cal.monthcalendar(year, month) + weeks = calendar.monthcalendar(year, month) month_days = list(itertools.chain.from_iterable([[0 for _ in range(8 - begin_at_sunday_plus)]] + weeks)) if month_days[6] == 0: month_days = month_days[7:] @@ -14296,12 +14333,24 @@ def popup_get_date(start_mon, start_day, start_year, begin_at_sunday_plus=0, no cur_year = start_year cur_day = start_day + + def get_month_name(month_no, locale): + with calendar.different_locale(locale): + return calendar.month_name[month_no] + + def get_day_name(day_no, locale): + with calendar.different_locale(locale): + return calendar.day_abbr[day_no] + + month_names = [get_month_name(month, locale) for month in range(1,13)] + day_names = [get_day_name(day, locale) for day in range(0,7)] + days_layout = make_days_layout() layout = [[B('◄', font=arrow_font, border_width=0, key='-MON-DOWN-'), - Text('{} {}'.format(cal.month_name[cur_month], cur_year), size=(16,1), justification='c', font=mon_year_font, key='-MON-YEAR-'), + Text('{} {}'.format(month_names[cur_month-1], cur_year), size=(16,1), justification='c', font=mon_year_font, key='-MON-YEAR-'), B('►', font=arrow_font,border_width=0, key='-MON-UP-')]] - layout += [[Col([[T(cal.day_abbr[i - (8 - begin_at_sunday_plus) % 7], size=(4,1), font=day_font, background_color=theme_text_color(), text_color=theme_background_color(), pad=(0,0)) for i in range(7)]], background_color=theme_text_color(), pad=(0,0))]] + layout += [[Col([[T(day_names[i - (8 - begin_at_sunday_plus) % 7], size=(4,1), font=day_font, background_color=theme_text_color(), text_color=theme_background_color(), pad=(0,0)) for i in range(7)]], background_color=theme_text_color(), pad=(0,0))]] layout += days_layout if not close_when_chosen: layout += [[Button('Ok', border_width=0,font='TkFixedFont 8'), Button('Cancel',border_width=0, font='TkFixedFont 8')]] @@ -14336,7 +14385,7 @@ def popup_get_date(start_mon, start_day, start_year, begin_at_sunday_plus=0, no elif cur_month < 1: cur_month = 12 cur_year -= 1 - window['-MON-YEAR-'].update('{} {}'.format(cal.month_name[cur_month], cur_year)) + window['-MON-YEAR-'].update('{} {}'.format(month_names[cur_month-1], cur_year)) update_days(window, cur_month, cur_year, begin_at_sunday_plus) if prev_choice: window[prev_choice].update(background_color=theme_background_color(), text_color=theme_text_color())