2011-09-25 1358 views
2

我正在構建一個下拉菜單,用於選擇開始日期。它有3個級聯,分別命名爲年,月,日。生成一天級聯的內容,以便可用天數與所選年份和月份一致。 在單個會話中,用戶可能/可能會多次更改日期。Tkinter菜單選擇日期

我的問題:當用戶第一次選擇年/月時,會生成days命令。此後,任何新年/月的組合,下面的代碼只是將命令添加到級聯。因此,這一天的級聯包含兩個月的日子。

我一直在努力使代碼刪除舊的菜單欄進入daymenu並重新創建它基於新的數據。 我想知道,如何對預先存在的運行菜單進行更改?我已經搜索了tkinter文檔,但不知道如何實現它。

import calendar as cal 
import Tkinter as tk 
import datetime 
import os.path 
window = tk.Tk() 



# Menu variables: 
year = tk.IntVar() 
month = tk.IntVar() 
day = tk.IntVar() 
hour = tk.IntVar() 
minute = tk.IntVar() 
dur_hour = tk.IntVar() 
dur_minute = tk.IntVar() 
duration = tk.StringVar() 
start = tk.StringVar() 

#   list initializations  

list_of_years = [] 
list_of_months = [] 
list_of_hours = [] 
list_of_days = [] 
list_of_minutes = [] 


def year_seter(value): 
    year.set(value) 
    all_for_day() 

def all_for_day(): #checks if the data needed to determine number of days in the month is present 
    list_of_days = [] 
    y = year.get() 
    m = month.get() 
    lenght_of_month = cal.monthrange(y,m) 
    lenght_of_month2 = lenght_of_month[1] 
    if m != 0 and y != 0: 
     make_daylist(lenght_of_month2) 
     make_daymenu() 

def month_seter(value): 
    month.set(value) 
    all_for_day() 

def day_seter(value): 
    day.set(value) 

def time_parameters(): 
    the_date = datetime.datetime(1,1,1,0,0,0,0) 
    the_date = the_date.now() 
    end_year = the_date.year 
    make_yearlist(1995, end_year) 
    make_monthlist() 
    make_hourlist() 
    make_minutelist() 

def make_yearlist(the_year, end_year): 
    while the_year <= end_year: 
     list_of_years.append(the_year) 
     the_year += 1 

def make_monthlist(): 
    for i in range(12): 
     list_of_months.append(i + 1) 

def make_daylist(num_days): 
    for i in range(num_days): 
     list_of_days.append(i + 1) 

def make_hourlist(): 
    for i in range(24): 
     list_of_hours.append(i) 

def make_minutelist(): 
    for i in range(60): 
     list_of_minutes.append(i) 

def make_daymenu(): 
    for the_day in list_of_days: 
     daymenu.add_command(label=the_day, command=lambda : day_seter(the_day)) 
    window.config(menu=menubar) 



# The following constructs the menu 
time_parameters() 
menubar = tk.Menu(window) 

yearmenu = tk.Menu(menubar) 
for the_year in list_of_years: 
    yearmenu.add_command(label=str(the_year), command=lambda the_year=the_year: year_seter(the_year)) 
menubar.add_cascade(label = 'Year', menu=yearmenu) 
window.config(menu=menubar) 

monthmenu = tk.Menu(menubar) 
for the_month in list_of_months: 
    monthmenu.add_command(label=the_month, command=lambda the_month=the_month: month_seter(the_month)) 
menubar.add_cascade(label = 'Month', menu=monthmenu) 
window.config(menu=menubar) 

daymenu = tk.Menu(menubar) 
menubar.add_cascade(label = 'Day', menu=daymenu) 
window.config(menu=menubar) 

window.mainloop() 

回答

2

你可以添加新的之前刪除daymenu所有條目:

def make_daymenu(): 
    daymenu.delete(0,31) 
    for the_day in list_of_days: 
     daymenu.add_command(label=the_day, command=lambda : day_setter(the_day)) 
    window.config(menu=menubar) 
+0

當然,所有的月份至少有28天,所以你需要添加或刪除更多的東西。 –

+0

@ByanOakley:我不太清楚如何實施你的建議。這不像使用'daymenu.delete(29,31)'那麼簡單,因爲那會重複1..28天。限制for循環只添加所需的日期需要找出菜單中已有的日期。如何做到這一點? – unutbu

+0

我也曾想過這個解決方案,但我仍然在學習基礎知識,所以我不知道如何實現它。無論如何,感謝你們兩位的投入。 – Sasha

0

碰到你的代碼,以選擇一個日期。最近不得不爲相似的目的寫一個簡單的日曆。我可以爲您提供該選項作爲替代方案。我覺得這個選項更方便選擇日期。

import calendar, datetime, Tkinter 

class calendarTk(Tkinter.Frame): # class calendarTk 
    """ Calendar, the current date is exposed today, or transferred to date""" 
    def __init__(self,master=None,date=None,dateformat="%d/%m/%Y",command=lambda i:None): 
     Tkinter.Frame.__init__(self, master) 
     self.dt=datetime.datetime.now() if date is None else datetime.datetime.strptime(date, dateformat) 
     self.showmonth() 
     self.command=command 
     self.dateformat=dateformat 
    def showmonth(self): # Show the calendar for a month 
     sc = calendar.month(self.dt.year, self.dt.month).split('\n') 
     for t,c in [('<<',0),('<',1),('>',5),('>>',6)]: # The buttons to the left to the right year and month 
      Tkinter.Button(self,text=t,relief='flat',command=lambda i=t:self.callback(i)).grid(row=0,column=c) 
     Tkinter.Label(self,text=sc[0]).grid(row=0,column=2,columnspan=3) # year and month 
     for line,lineT in [(i,sc[i+1]) for i in range(1,len(sc)-1)]: # The calendar 
      for col,colT in [(i,lineT[i*3:(i+1)*3-1]) for i in range(7)]: # For each element 
       obj=Tkinter.Button if colT.strip().isdigit() else Tkinter.Label # If this number is a button, or Label 
       args={'command':lambda i=colT:self.callback(i)} if obj==Tkinter.Button else {} # If this button, then fasten it to the command 
       bg='green' if colT.strip()==str(self.dt.day) else 'SystemButtonFace' # If the date coincides with the day of date - make him a green background 
       fg='red' if col>=5 else 'SystemButtonText' # For the past two days, the color red 
       obj(self,text="%s"% colT,relief='flat',bg=bg,fg=fg,**args).grid(row=line, column=col, ipadx=2, sticky='nwse') # Draw Button or Label 
    def callback(self,but): # Event on the button 
     if but.strip().isdigit(): self.dt=self.dt.replace(day=int(but)) # If you clicked on a date - the date change 
     elif but in ['<','>','<<','>>']: 
      day=self.dt.day 
      if but in['<','>']: self.dt=self.dt+datetime.timedelta(days=30 if but=='>' else -30) # Move a month in advance/rewind 
      if but in['<<','>>']: self.dt=self.dt+datetime.timedelta(days=365 if but=='>>' else -365) # Year forward/backward 
      try: self.dt=self.dt.replace(day=day) # We are trying to put the date on which stood 
      except: pass       # It is not always possible 
     self.showmonth() # Then always show calendar again 
     if but.strip().isdigit(): self.command(self.dt.strftime(self.dateformat)) # If it was a date, then call the command 

if __name__ == '__main__': 
    def com(f): print f 
    root = Tkinter.Tk() 
    root.title("Monthly Calendar") 
    c=calendarTk(root,date="21/11/2006",dateformat="%d/%m/%Y",command=com) 
    c.pack() 

    root.mainloop()