2010-12-14 24 views
22

Esiste un modo standard con cui le app di tkinter consentono all'utente di scegliere una data?Come posso creare un selettore di date in tkinter?

+0

Impropable, come tkinter è molto minimalista. Se vuoi qualcosa di sofisticato senza costruirlo tu stesso, la soluzione migliore è uno dei più grandi toolkit GUI con batterie (consiglio Qt). – delnan

+9

+1 domanda assolutamente ragionevole. Questo è il tipo di cosa dell'interfaccia utente che dovrebbe essere standardizzata all'interno di un kit di strumenti. Tk sorpreso non lo offre. – Anne

risposta

14

No, Tk non include un widget di selezione data. Ci sono un paio di Python widget del calendario si potrebbe provare:

http://svn.python.org/projects/sandbox/trunk/ttk-gsoc/samples/ttkcalendar.py

http://effbot.org/zone/wcklib-calendar.htm

+0

Grazie, gli darò un'occhiata. La mia domanda era - dal momento che non hanno un widget - cosa hanno fatto la maggior parte degli sviluppatori di tk/tkinter? Hai solo tre spin box? Che dire di diversi mesi? Che dire degli anni bisestili? – MKaras

+2

parlando come uno sviluppatore ex-tcl/tk, ho semplicemente fatto il mio proprio le poche volte che ne avevo bisogno. Sono abbastanza banali da creare poiché tcl (e python) hanno routine di date che possono fornirti i dati. Tutto ciò che devi fare è creare una griglia di pulsanti o qualcosa di simile. –

+1

Sì, lo stesso qui; Tcl/Tk (e Tkinter) rendono molto banale la creazione di nuovi widget. Se vuoi una struttura controlla il Widget Construction Kit (usato dal calendario WCK linkato sopra). –

5

Non per quanto ho potuto trovare. Per chi vuole fare questo in futuro:

ho usato tkSimpleDialog e ttkcalendar.py (con modificazioni dalla this SO post) per fare un CalendarDialog. I tre file sono disponibili sul mio github.

Di seguito si riporta il codice nel mio 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() 
+2

Heh, il file sorgente Python che hai collegato in realtà non ha HANNO quelle modifiche in esso - incappato in un ostacolo fino a quando ho capito che doveva essere modificato per farlo giocare con una vera app Tkinter: P –

+0

Sì, ecco perché Ho collegato anche le versioni patch sul mio github. – Moshe

+0

Ahh, grazie, grazie. Ho appena dato per scontato che i link fossero tutti nello stesso posto perché non li avevo letti abbastanza vicino per vedere che non erano tutti github: P –

0

Questo è il modo in cui codificare un datepicker pitone in Tkinter.

# !/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() 
Problemi correlati