11import tkinter as tk
22import re
33from datetime import datetime
4+ from typing import TYPE_CHECKING
45
56try :
67 from tkcalendar import Calendar
78except ImportError :
89 Calendar = None
910
10- class DateEntry (tk .Frame ):
11- def __init__ (self , master = None , ** kwargs ):
11+ from ..types import DatetimeTag
12+ if TYPE_CHECKING :
13+ from tk_window import TkWindow
14+
15+
16+ class DateEntryFrame (tk .Frame ):
17+ def __init__ (self , master , tk_app : "TkWindow" , tag : DatetimeTag , variable : tk .Variable , ** kwargs ):
1218 super ().__init__ (master , ** kwargs )
13- self .create_widgets ()
14- self .pack (expand = True , fill = tk .BOTH )
19+
20+ self .tk_app = tk_app
21+ self .tag = tag
22+
23+ # Date entry
24+ self .spinbox = self .create_spinbox (variable )
25+
26+ # Frame holding the calendar
27+ self .frame = tk .Frame (self )
28+
29+ # The calendar widget
30+ if Calendar :
31+ # Toggle calendar button
32+ tk .Button (self , text = "…" , command = self .toggle_calendar ).grid (row = 0 , column = 1 )
33+
34+ # Add a calendar widget
35+ self .calendar = Calendar (self .frame , selectmode = 'day' , date_pattern = 'yyyy-mm-dd' )
36+ # Bind date selection event
37+ self .calendar .bind ("<<CalendarSelected>>" , self .on_date_select )
38+ self .calendar .grid ()
39+ # Initialize calendar with the current date
40+ self .update_calendar (self .spinbox .get (), '%Y-%m-%d %H:%M:%S.%f' )
41+ else :
42+ self .calendar = None
43+
1544 self .bind_all_events ()
1645
17- def create_widgets (self ):
18- self .spinbox = tk .Spinbox (self , font = ("Arial" , 16 ), width = 30 , wrap = True )
19- self .spinbox .pack (padx = 20 , pady = 20 )
20- self .spinbox .insert (0 , datetime .now ().strftime ("%Y-%m-%d %H:%M:%S.%f" )[:- 4 ])
21- self .spinbox .focus_set ()
22- self .spinbox .icursor (8 )
46+ def create_spinbox (self , variable : tk .Variable ):
47+ spinbox = tk .Spinbox (self , font = ("Arial" , 16 ), width = 30 , wrap = True , textvariable = variable )
48+ spinbox .grid ()
49+ if not variable .get ():
50+ spinbox .insert (0 , datetime .now ().strftime ("%Y-%m-%d %H:%M:%S.%f" )[:- 4 ])
51+ spinbox .focus_set ()
52+ spinbox .icursor (8 )
2353
2454 # Bind up/down arrow keys
25- self . spinbox .bind ("<Up>" , self .increment_value )
26- self . spinbox .bind ("<Down>" , self .decrement_value )
55+ spinbox .bind ("<Up>" , self .increment_value )
56+ spinbox .bind ("<Down>" , self .decrement_value )
2757
2858 # Bind mouse click on spinbox arrows
29- self . spinbox .bind ("<ButtonRelease-1>" , self .on_spinbox_click )
59+ spinbox .bind ("<ButtonRelease-1>" , self .on_spinbox_click )
3060
3161 # Bind key release event to update calendar when user changes the input field
32- self .spinbox .bind ("<KeyRelease>" , self .on_spinbox_change )
33-
34- # Toggle calendar button
35- self .toggle_button = tk .Button (self , text = "Show/Hide Calendar" , command = self .toggle_calendar )
36- self .toggle_button .pack (pady = 10 )
37-
38- if Calendar :
39- self .create_calendar ()
62+ spinbox .bind ("<KeyRelease>" , self .on_spinbox_change )
63+ return spinbox
4064
4165 def bind_all_events (self ):
4266 # Copy to clipboard with ctrl+c
@@ -51,27 +75,15 @@ def bind_all_events(self):
5175 # Toggle calendar widget with ctrl+shift+c
5276 self .bind_all ("<Control-Shift-C>" , lambda event : self .toggle_calendar ())
5377
54- def create_calendar (self ):
55- # Create a frame to hold the calendar
56- self .frame = tk .Frame (self )
57- self .frame .pack (padx = 20 , pady = 20 , expand = True , fill = tk .BOTH )
58-
59- # Add a calendar widget
60- self .calendar = Calendar (self .frame , selectmode = 'day' , date_pattern = 'yyyy-mm-dd' )
61- self .calendar .place (relwidth = 0.7 , relheight = 0.8 , anchor = 'n' , relx = 0.5 )
62-
63- # Bind date selection event
64- self .calendar .bind ("<<CalendarSelected>>" , self .on_date_select )
65-
66- # Initialize calendar with the current date
67- self .update_calendar (self .spinbox .get (), '%Y-%m-%d %H:%M:%S.%f' )
68-
6978 def toggle_calendar (self , event = None ):
70- if Calendar :
71- if hasattr (self , 'frame' ) and self .frame .winfo_ismapped ():
72- self .frame .pack_forget ()
73- else :
74- self .frame .pack (padx = 20 , pady = 20 , expand = True , fill = tk .BOTH )
79+ if not self .calendar :
80+ return
81+ if self .calendar .winfo_ismapped ():
82+ self .frame .grid_forget ()
83+ else :
84+ self .frame .grid (row = 1 , column = 0 )
85+ self .tk_app ._refresh_size ()
86+ return
7587
7688 def increment_value (self , event = None ):
7789 self .change_date (1 )
@@ -112,7 +124,8 @@ def change_date(self, delta):
112124 split_input [part_index ] = str (new_number ).zfill (len (split_input [part_index ]))
113125
114126 if time :
115- new_value_str = f"{ split_input [0 ]} -{ split_input [1 ]} -{ split_input [2 ]} { split_input [3 ]} :{ split_input [4 ]} :{ split_input [5 ]} .{ split_input [6 ][:2 ]} "
127+ new_value_str = f"{ split_input [0 ]} -{ split_input [1 ]} -{ split_input [2 ]} " \
128+ f"{ split_input [3 ]} :{ split_input [4 ]} :{ split_input [5 ]} .{ split_input [6 ][:2 ]} "
116129 string_format = '%Y-%m-%d %H:%M:%S.%f'
117130 else :
118131 new_value_str = f"{ split_input [0 ]} -{ split_input [1 ]} -{ split_input [2 ]} "
@@ -139,9 +152,9 @@ def get_part_index(self, caret_pos, split_length):
139152 elif split_length > 3 :
140153 if caret_pos < 14 : # hour
141154 return 3
142- elif caret_pos < 17 : # minute
155+ elif caret_pos < 17 : # minute
143156 return 4
144- elif caret_pos < 20 : # second
157+ elif caret_pos < 20 : # second
145158 return 5
146159 else : # millisecond
147160 return 6
@@ -187,7 +200,7 @@ def show_popup(self, message):
187200 # Position the popup window in the top-left corner of the widget
188201 x = self .winfo_rootx ()
189202 y = self .winfo_rooty ()
190-
203+
191204 # Position of the popup window has to be "inside" the main window or it will be focused on popup
192205 popup .geometry (f"400x100+{ x + 200 } +{ y - 150 } " )
193206
@@ -197,7 +210,6 @@ def show_popup(self, message):
197210 # Keep focus on the spinbox
198211 self .spinbox .focus_force ()
199212
200-
201213 def select_all (self , event = None ):
202214 self .spinbox .selection_range (0 , tk .END )
203215 self .spinbox .focus_set ()
@@ -207,31 +219,3 @@ def select_all(self, event=None):
207219 def paste_from_clipboard (self , event = None ):
208220 self .spinbox .delete (0 , tk .END )
209221 self .spinbox .insert (0 , self .clipboard_get ())
210-
211- if __name__ == "__main__" :
212- root = tk .Tk ()
213- # Get the screen width and height
214- # This is calculating the position of the TOTAL dimentions of all screens combined
215- # How to calculate the position of the window on the current screen?
216- screen_width = root .winfo_screenwidth ()
217- screen_height = root .winfo_screenheight ()
218-
219- print (screen_width , screen_height )
220-
221- # Calculate the position to center the window
222- x = (screen_width // 2 ) - 400
223- y = (screen_height // 2 ) - 600
224-
225- print (x , y )
226-
227- # Set the position of the window
228- root .geometry (f"800x600+{ x } +{ y } " )
229- # keep the main widget on top all the time
230- root .wm_attributes ("-topmost" , False )
231- root .wm_attributes ("-topmost" , True )
232- root .title ("Date Editor" )
233-
234- date_entry = DateEntry (root )
235- date_entry .pack (expand = True , fill = tk .BOTH )
236- root .mainloop ()
237-
0 commit comments