4 changed files with 221 additions and 2 deletions
@ -0,0 +1,143 @@ |
|||||||
|
# MIT License |
||||||
|
# |
||||||
|
# Copyright (c) 2025 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com> |
||||||
|
# |
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy |
||||||
|
# of this software and associated documentation files (the "Software"), to deal |
||||||
|
# in the Software without restriction, including without limitation the rights |
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||||
|
# copies of the Software, and to permit persons to whom the Software is |
||||||
|
# furnished to do so, subject to the following conditions: |
||||||
|
# |
||||||
|
# The above copyright notice and this permission notice shall be included in all |
||||||
|
# copies or substantial portions of the Software. |
||||||
|
# |
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||||
|
# SOFTWARE. |
||||||
|
|
||||||
|
__all__ = ['TTkDateTime'] |
||||||
|
|
||||||
|
from enum import IntEnum,Enum,auto |
||||||
|
from dataclasses import dataclass |
||||||
|
import datetime as dt |
||||||
|
|
||||||
|
from typing import Optional |
||||||
|
|
||||||
|
from TermTk.TTkCore.color import TTkColor |
||||||
|
from TermTk.TTkCore.string import TTkString |
||||||
|
from TermTk.TTkCore.constant import TTkK |
||||||
|
from TermTk.TTkCore.signal import pyTTkSignal, pyTTkSlot |
||||||
|
from TermTk.TTkCore.TTkTerm.inputkey import TTkKeyEvent |
||||||
|
from TermTk.TTkCore.TTkTerm.inputmouse import TTkMouseEvent |
||||||
|
from TermTk.TTkLayouts import TTkGridLayout, TTkLayout |
||||||
|
from TermTk.TTkWidgets.widget import TTkWidget |
||||||
|
from TermTk.TTkWidgets.container import TTkContainer |
||||||
|
from TermTk.TTkWidgets.spinbox import TTkSpinBox |
||||||
|
from TermTk.TTkWidgets.datetime_date import TTkDate |
||||||
|
from TermTk.TTkWidgets.datetime_time import TTkTime |
||||||
|
|
||||||
|
class TTkDateTime(TTkContainer): |
||||||
|
''' TTkDateTime: |
||||||
|
|
||||||
|
A composite widget for displaying and editing date and time values. |
||||||
|
|
||||||
|
Combines :class:`~TermTk.TTkWidgets.datetime_date.TTkDate` and :class:`~TermTk.TTkWidgets.datetime_time.TTkTime` widgets |
||||||
|
into a single datetime editor. |
||||||
|
|
||||||
|
:: |
||||||
|
|
||||||
|
2025/11/04 📅 12:30:45 |
||||||
|
|
||||||
|
.. code:: python |
||||||
|
|
||||||
|
import TermTk as ttk |
||||||
|
|
||||||
|
root = ttk.TTk(mouseTrack=True) |
||||||
|
|
||||||
|
ttk.TTkDateTime(parent=root) # Defaults to the current datetime |
||||||
|
|
||||||
|
root.mainloop() |
||||||
|
|
||||||
|
:param datetime: The initial datetime to display, defaults to the current datetime. |
||||||
|
:type datetime: :py:class:`datetime.datetime`, optional |
||||||
|
''' |
||||||
|
|
||||||
|
__slots__ = ( |
||||||
|
'_datetime', |
||||||
|
'_dateWidget', '_timeWidget', |
||||||
|
# Signals |
||||||
|
'datetimeChanged') |
||||||
|
|
||||||
|
datetimeChanged:pyTTkSignal |
||||||
|
''' |
||||||
|
This signal is emitted whenever the datetime changes. |
||||||
|
|
||||||
|
:param datetime: The new datetime value |
||||||
|
:type datetime: :py:class:`datetime.datetime` |
||||||
|
''' |
||||||
|
|
||||||
|
_datetime:dt.datetime |
||||||
|
_dateWidget:TTkDate |
||||||
|
_timeWidget:TTkTime |
||||||
|
|
||||||
|
def __init__(self, *, |
||||||
|
datetime:Optional[dt.datetime]=None, |
||||||
|
**kwargs) -> None: |
||||||
|
''' |
||||||
|
Initializes the TTkDateTime widget. |
||||||
|
|
||||||
|
:param datetime: The initial datetime to display. If None, the current datetime is used. |
||||||
|
:type datetime: :py:class:`datetime.datetime`, optional |
||||||
|
''' |
||||||
|
self.datetimeChanged = pyTTkSignal(dt.datetime) |
||||||
|
if not datetime: |
||||||
|
datetime = dt.datetime.now().replace(microsecond=0) |
||||||
|
self._datetime = datetime |
||||||
|
_layout=TTkLayout() |
||||||
|
size = (13+1+8,1) |
||||||
|
super().__init__(**kwargs|{'layout':_layout, 'size':size, 'minSize':size}) |
||||||
|
self._dateWidget = TTkDate(parent=self, pos=( 0,0), date=datetime.date()) |
||||||
|
self._timeWidget = TTkTime(parent=self, pos=(14,0), time=datetime.time()) |
||||||
|
self._dateWidget.dateChanged.connect(self._somethingChanged) |
||||||
|
self._timeWidget.timeChanged.connect(self._somethingChanged) |
||||||
|
|
||||||
|
@pyTTkSlot() |
||||||
|
def _somethingChanged(self) -> None: |
||||||
|
''' |
||||||
|
Internal slot that synchronizes the datetime value when either date or time changes. |
||||||
|
''' |
||||||
|
self.setDatetime( |
||||||
|
self._datetime.combine( |
||||||
|
date=self._dateWidget.date(), |
||||||
|
time=self._timeWidget.time())) |
||||||
|
|
||||||
|
def datetime(self) -> dt.datetime: |
||||||
|
''' |
||||||
|
Returns the current datetime of the widget. |
||||||
|
|
||||||
|
:return: The current datetime |
||||||
|
:rtype: :py:class:`datetime.datetime` |
||||||
|
''' |
||||||
|
return self._datetime |
||||||
|
|
||||||
|
@pyTTkSlot(dt.datetime) |
||||||
|
def setDatetime(self, datetime:dt.datetime) -> None: |
||||||
|
''' |
||||||
|
Sets the current datetime of the widget. |
||||||
|
|
||||||
|
This updates both the internal date and time widgets and emits the |
||||||
|
:py:attr:`datetimeChanged` signal if the value changes. |
||||||
|
|
||||||
|
:param datetime: The new datetime to set |
||||||
|
:type datetime: :py:class:`datetime.datetime` |
||||||
|
''' |
||||||
|
if datetime != self._datetime: |
||||||
|
self._datetime = datetime |
||||||
|
self._dateWidget.setDate(datetime.date()) |
||||||
|
self._timeWidget.setTime(datetime.time()) |
||||||
|
self.datetimeChanged.emit(datetime) |
||||||
@ -0,0 +1,76 @@ |
|||||||
|
#!/usr/bin/env python3 |
||||||
|
|
||||||
|
# MIT License |
||||||
|
# |
||||||
|
# Copyright (c) 2021 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com> |
||||||
|
# |
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy |
||||||
|
# of this software and associated documentation files (the "Software"), to deal |
||||||
|
# in the Software without restriction, including without limitation the rights |
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||||
|
# copies of the Software, and to permit persons to whom the Software is |
||||||
|
# furnished to do so, subject to the following conditions: |
||||||
|
# |
||||||
|
# The above copyright notice and this permission notice shall be included in all |
||||||
|
# copies or substantial portions of the Software. |
||||||
|
# |
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||||
|
# SOFTWARE. |
||||||
|
|
||||||
|
import sys, os |
||||||
|
from datetime import time,date,datetime |
||||||
|
|
||||||
|
sys.path.append(os.path.join(sys.path[0],'../../libs/pyTermTk')) |
||||||
|
import TermTk as ttk |
||||||
|
|
||||||
|
root = ttk.TTk(mouseTrack=True) |
||||||
|
winLog = ttk.TTkWindow(parent=root, pos=(20,1), size=(80,30), layout=ttk.TTkGridLayout()) |
||||||
|
ttk.TTkLogViewer(parent=winLog) |
||||||
|
|
||||||
|
win = ttk.TTkWindow(parent=root, pos=( 0,0), size=(57,14), title='Generic') |
||||||
|
win1 = ttk.TTkWindow(parent=root, pos=( 60,0), size=(22,12), title='Date Form', layout=ttk.TTkGridLayout()) |
||||||
|
win2 = ttk.TTkWindow(parent=root, pos=( 85,0), size=(15,12), title='Date') |
||||||
|
win3 = ttk.TTkWindow(parent=root, pos=(103,0), size=(25,12), title='DateTime') |
||||||
|
|
||||||
|
testTime1=time(hour=3,minute=30) |
||||||
|
timeWidget1 = ttk.TTkTime(parent=win, pos=(1,0), time=testTime1) |
||||||
|
timeWidget2 = ttk.TTkTime(parent=win, pos=(1,2)) |
||||||
|
|
||||||
|
timeLabel1 = ttk.TTkLabel(parent=win, pos=(1,4), text=str(testTime1)) |
||||||
|
timeLabel2 = ttk.TTkLabel(parent=win, pos=(1,6), text=str(timeWidget2.time())) |
||||||
|
timeWidget1.timeChanged.connect(lambda _t:timeLabel1.setText(str(_t))) |
||||||
|
timeWidget2.timeChanged.connect(lambda _t:timeLabel2.setText(str(_t))) |
||||||
|
|
||||||
|
testDate = date(year=1980, month=12, day=25) |
||||||
|
dateFormWidget1 = ttk.TTkDateForm(parent=win, pos=(12,0), date=testDate) |
||||||
|
dateFormWidget2 = ttk.TTkDateForm(parent=win, pos=(34,0)) |
||||||
|
dateFormWidget3 = ttk.TTkDateForm(parent=win1, date=testDate.replace(year=2000)) |
||||||
|
dateLabel = ttk.TTkLabel(parent=win, pos=(1,8), text=str(testDate)) |
||||||
|
dateFormWidget1.dateChanged.connect(lambda _d: dateLabel.setText(str(_d))) |
||||||
|
dateFormWidget1.dateChanged.connect(dateFormWidget2.setDate) |
||||||
|
dateFormWidget2.dateChanged.connect(dateFormWidget1.setDate) |
||||||
|
dateFormWidget3.dateChanged.connect(dateFormWidget2.setDate) |
||||||
|
|
||||||
|
dateWidget1 = ttk.TTkDate(parent=win2, pos=(0,0), date=testDate) |
||||||
|
dateWidget2 = ttk.TTkDate(parent=win2, pos=(0,2)) |
||||||
|
dateLabel1 = ttk.TTkLabel(parent=win2, pos=(0,4), text=str(testDate)) |
||||||
|
dateLabel2 = ttk.TTkLabel(parent=win2, pos=(0,6), text=str(dateWidget2.date())) |
||||||
|
dateWidget1.dateChanged.connect(lambda _d:dateLabel1.setText(str(_d))) |
||||||
|
dateWidget1.dateChanged.connect(dateFormWidget1.setDate) |
||||||
|
dateWidget2.dateChanged.connect(lambda _d:dateLabel2.setText(str(_d))) |
||||||
|
|
||||||
|
testDatetime = datetime(1995,10,5, 23,30,5) |
||||||
|
dateTimeWidget1 = ttk.TTkDateTime(parent=win3, pos=(0,0)) |
||||||
|
dateTimeWidget2 = ttk.TTkDateTime(parent=win3, pos=(0,4), datetime=testDatetime) |
||||||
|
datetimeLabel1 = ttk.TTkLabel(parent=win3, pos=(0,2), text=str(dateTimeWidget1.datetime())) |
||||||
|
datetimeLabel2 = ttk.TTkLabel(parent=win3, pos=(0,6), text=str(testDatetime)) |
||||||
|
dateTimeWidget1.datetimeChanged.connect(lambda _d:datetimeLabel1.setText(str(_d))) |
||||||
|
dateTimeWidget1.datetimeChanged.connect(dateTimeWidget2.setDatetime) |
||||||
|
dateTimeWidget2.datetimeChanged.connect(lambda _d:datetimeLabel2.setText(str(_d))) |
||||||
|
|
||||||
|
root.mainloop() |
||||||
Loading…
Reference in new issue