如何在 tkinter 中创建日期选择器?
Posted
技术标签:
【中文标题】如何在 tkinter 中创建日期选择器?【英文标题】:How do I create a date picker in tkinter? 【发布时间】:2011-05-25 12:48:36 【问题描述】:tkinter 应用程序是否有任何标准方式允许用户选择日期?
【问题讨论】:
不合适,因为 tkinter 非常简约。如果你想要一些花哨的东西而不自己构建它,你最好的选择是更大的、包含电池的 GUI 工具包之一(我推荐 Qt)。 +1 完全合理的问题。这是一种应该在工具包中标准化的 UI。惊讶的 tk 不提供。 【参考方案1】:不,但您可以从用户那里获取它作为格式化字符串中的日期时间元素..
例子:
import datetime
userdatestring = '2013-05-10'
thedate = datetime.datetime.strptime(userdatestring, '%Y-%m-%d')
查看http://docs.python.org/2/library/datetime.html#strftime-strptime-behavior。它很方便,虽然不是最用户友好的约会方式。
【讨论】:
【参考方案2】:我找不到。对于将来想要这样做的任何人:
我使用tkSimpleDialog 和ttkcalendar.py(对this SO 帖子进行了修改)制作了CalendarDialog。这三个文件的修改版本可以在我的github上找到。
下面是我CalendarDialog.py中的代码:
import Tkinter
import ttkcalendar
import tkSimpleDialog
class CalendarDialog(tkSimpleDialog.Dialog):
"""Dialog box that displays a calendar and returns the selected date"""
def body(self, master):
self.calendar = ttkcalendar.Calendar(master)
self.calendar.pack()
def apply(self):
self.result = self.calendar.selection
# Demo code:
def main():
root = Tkinter.Tk()
root.wm_title("CalendarDialog Demo")
def onclick():
cd = CalendarDialog(root)
print cd.result
button = Tkinter.Button(root, text="Click me to see a calendar!", command=onclick)
button.pack()
root.update()
root.mainloop()
if __name__ == "__main__":
main()
【讨论】:
嘿,您链接的 python 源文件实际上并没有这些修改 - 遇到了一个绊脚石,直到我意识到必须对其进行修改才能使其与实际的 Tkinter 应用程序配合得很好:P 是的,这就是为什么我也链接到我的 github 上的修补版本。 啊,明白了,谢谢。我只是假设链接都到了同一个地方,因为我没有仔细阅读它们,看它们不都是 github :P【参考方案3】:这就是我们在 tkinter 中编写 python 日期选择器的方式。
# !/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: Rambarun Komaljeet
# License: Freeware
# ---------------------------------------------------------------------------
import calendar
import tkinter as tk
import time
from tkinter import ttk
class MyDatePicker(tk.Toplevel):
"""
Description:
A tkinter GUI date picker.
"""
def __init__(self, widget=None, format_str=None):
"""
:param widget: widget of parent instance.
:param format_str: print format in which to display date.
:type format_str: string
Example::
a = MyDatePicker(self, widget=self.parent widget,
format_str='%02d-%s-%s')
"""
super().__init__()
self.widget = widget
self.str_format = format_str
self.title("Date Picker")
self.resizable(0, 0)
self.geometry("+630+390")
self.init_frames()
self.init_needed_vars()
self.init_month_year_labels()
self.init_buttons()
self.space_between_widgets()
self.fill_days()
self.make_calendar()
def init_frames(self):
self.frame1 = tk.Frame(self)
self.frame1.pack()
self.frame_days = tk.Frame(self)
self.frame_days.pack()
def init_needed_vars(self):
self.month_names = tuple(calendar.month_name)
self.day_names = tuple(calendar.day_abbr)
self.year = time.strftime("%Y")
self.month = time.strftime("%B")
def init_month_year_labels(self):
self.year_str_var = tk.StringVar()
self.month_str_var = tk.StringVar()
self.year_str_var.set(self.year)
self.year_lbl = tk.Label(self.frame1, textvariable=self.year_str_var,
width=3)
self.year_lbl.grid(row=0, column=5)
self.month_str_var.set(self.month)
self.month_lbl = tk.Label(self.frame1, textvariable=self.month_str_var,
width=8)
self.month_lbl.grid(row=0, column=1)
def init_buttons(self):
self.left_yr = ttk.Button(self.frame1, text="←", width=5,
command=self.prev_year)
self.left_yr.grid(row=0, column=4)
self.right_yr = ttk.Button(self.frame1, text="→", width=5,
command=self.next_year)
self.right_yr.grid(row=0, column=6)
self.left_mon = ttk.Button(self.frame1, text="←", width=5,
command=self.prev_month)
self.left_mon.grid(row=0, column=0)
self.right_mon = ttk.Button(self.frame1, text="→", width=5,
command=self.next_month)
self.right_mon.grid(row=0, column=2)
def space_between_widgets(self):
self.frame1.grid_columnconfigure(3, minsize=40)
def prev_year(self):
self.prev_yr = int(self.year_str_var.get()) - 1
self.year_str_var.set(self.prev_yr)
self.make_calendar()
def next_year(self):
self.next_yr = int(self.year_str_var.get()) + 1
self.year_str_var.set(self.next_yr)
self.make_calendar()
def prev_month(self):
index_current_month = self.month_names.index(self.month_str_var.get())
index_prev_month = index_current_month - 1
# index 0 is empty string, use index 12 instead,
# which is index of December.
if index_prev_month == 0:
self.month_str_var.set(self.month_names[12])
else:
self.month_str_var.set(self.month_names[index_current_month - 1])
self.make_calendar()
def next_month(self):
index_current_month = self.month_names.index(self.month_str_var.get())
try:
self.month_str_var.set(self.month_names[index_current_month + 1])
except IndexError:
# index 13 does not exist, use index 1 instead, which is January.
self.month_str_var.set(self.month_names[1])
self.make_calendar()
def fill_days(self):
col = 0
# Creates days label
for day in self.day_names:
self.lbl_day = tk.Label(self.frame_days, text=day)
self.lbl_day.grid(row=0, column=col)
col += 1
def make_calendar(self):
# Delete date buttons if already present.
# Each button must have its own instance attribute for this to work.
try:
for dates in self.m_cal:
for date in dates:
if date == 0:
continue
self.delete_buttons(date)
except AttributeError:
pass
year = int(self.year_str_var.get())
month = self.month_names.index(self.month_str_var.get())
self.m_cal = calendar.monthcalendar(year, month)
# build dates buttons.
for dates in self.m_cal:
row = self.m_cal.index(dates) + 1
for date in dates:
col = dates.index(date)
if date == 0:
continue
self.make_button(str(date), str(row), str(col))
def make_button(self, date, row, column):
"""
Description:
Build a date button.
:param date: date.
:type date: string
:param row: row number.
:type row: string
:param column: column number.
:type column: string
"""
exec(
"self.btn_" + date + " = ttk.Button(self.frame_days, text=" + date
+ ", width=5)\n"
"self.btn_" + date + ".grid(row=" + row + " , column=" + column
+ ")\n"
"self.btn_" + date + ".bind(\"<Button-1>\", self.get_date)"
)
def delete_buttons(self, date):
"""
Description:
Delete a date button.
:param date: date.
:type: string
"""
exec(
"self.btn_" + str(date) + ".destroy()"
)
def get_date(self, clicked=None):
"""
Description:
Get the date from the calendar on button click.
:param clicked: button clicked event.
:type clicked: tkinter event
"""
clicked_button = clicked.widget
year = self.year_str_var.get()
month = self.month_str_var.get()
date = clicked_button['text']
self.full_date = self.str_format % (date, month, year)
print(self.full_date)
# Replace with parent 'widget' of your choice.
try:
self.widget.delete(0, tk.END)
self.widget.insert(0, self.full_date)
except AttributeError:
pass
if __name__ == '__main__':
def application():
MyDatePicker(format_str='%02d-%s-%s')
root = tk.Tk()
btn = tk.Button(root, text="test", command=application)
btn.pack()
root.mainloop()
【讨论】:
请显示错误信息。Alsp 请注意这是 python 3 代码。 其实我用的是python 2。错误开始找不到“super()”。【参考方案4】:如果有人仍然需要这个 - 这是一个使用 tkcalendar 包创建日历和 DateEntry 小部件的简单代码。
pip install tkcalendar
(用于安装包)
try:
import tkinter as tk
from tkinter import ttk
except ImportError:
import Tkinter as tk
import ttk
from tkcalendar import Calendar, DateEntry
def example1():
def print_sel():
print(cal.selection_get())
top = tk.Toplevel(root)
cal = Calendar(top,
font="Arial 14", selectmode='day',
cursor="hand1", year=2018, month=2, day=5)
cal.pack(fill="both", expand=True)
ttk.Button(top, text="ok", command=print_sel).pack()
def example2():
top = tk.Toplevel(root)
ttk.Label(top, text='Choose date').pack(padx=10, pady=10)
cal = DateEntry(top, width=12, background='darkblue',
foreground='white', borderwidth=2)
cal.pack(padx=10, pady=10)
root = tk.Tk()
s = ttk.Style(root)
s.theme_use('clam')
ttk.Button(root, text='Calendar', command=example1).pack(padx=10, pady=10)
ttk.Button(root, text='DateEntry', command=example2).pack(padx=10, pady=10)
root.mainloop()
【讨论】:
【参考方案5】:您应该安装 tkcalendar 模块。为此使用 pip3:
pip3 install tkcalendar
安装后,您可以在代码中导入模块。
使用这个:
from tkcalendar import Calendar
【讨论】:
【参考方案6】:尝试以下方法:
from tkinter import *
from tkcalendar import Calendar,DateEntry
root = Tk()
cal = DateEntry(root,width=30,bg="darkblue",fg="white",year=2010)
cal.grid()
root.mainloop()
tkcalendar
库应该通过pip install tkcalender
命令下载和安装。
【讨论】:
【参考方案7】:这里的答案提供了您所要求的大部分内容,但我觉得没有一个是完全令人满意的。作为一个 Tkinter 新手,我需要更多的支持。我的抱怨:
-
假设我希望日历默认为 2012 年的日期而不是今天的日期,
不将结果作为变量返回以供将来使用,
进入日历之前不必要的顶层菜单,以及
做出选择后不清理窗口并退出主循环。
感谢之前对我帮助很大的答案,这是我的版本。
def get_date():
import tkinter as tk
from tkinter import ttk
from tkcalendar import Calendar, DateEntry
def cal_done():
top.withdraw()
root.quit()
root = tk.Tk()
root.withdraw() # keep the root window from appearing
top = tk.Toplevel(root)
cal = Calendar(top,
font="Arial 14", selectmode='day',
cursor="hand1")
cal.pack(fill="both", expand=True)
ttk.Button(top, text="ok", command=cal_done).pack()
selected_date = None
root.mainloop()
return cal.selection_get()
selection = get_date()
print(selection)
【讨论】:
有趣的是如何在get_date
函数中定义cal_done
。我以前只在类和主线中看到过它。
这是完美的。非常感谢你。以上是关于如何在 tkinter 中创建日期选择器?的主要内容,如果未能解决你的问题,请参考以下文章