Python 特金特网格重叠
我正在创建一个日历,允许用户通过按上个月和下个月创建的按钮来循环月和年。基本上,我希望主窗口在单击“上一个月”或“下一个月”时使用正确的日期更新新的月份,它会这样做,唯一的问题是在循环时显示月份的特定日期重叠的日期按钮。 以下是我遇到的问题:Python 特金特网格重叠,python,tkinter,Python,Tkinter,我正在创建一个日历,允许用户通过按上个月和下个月创建的按钮来循环月和年。基本上,我希望主窗口在单击“上一个月”或“下一个月”时使用正确的日期更新新的月份,它会这样做,唯一的问题是在循环时显示月份的特定日期重叠的日期按钮。 以下是我遇到的问题: def prevMonth(self): try: self.grid_forget() #SHOULD REFRESH THE WINDOW SO BUTTONS DONT OVERLAP
def prevMonth(self):
try:
self.grid_forget()
#SHOULD REFRESH THE WINDOW SO BUTTONS DONT OVERLAP
print "forgeting"
except:
print "passed the forgetting"
pass
lastMonth = self.month - 1
self.month = lastMonth
self.curr_month()
def nextMonth(self):
try:
self.grid_forget()
#SHOULD REFRESH THE WINDOW SO BUTTONS DONT OVERLAP
print "forgeting"
except:
print "passed the forgetting"
pass
nextMonth = self.month + 1
self.month = nextMonth
self.curr_month()
当程序在月与月之间迭代时,网格不会刷新,它只是与日和月重叠。我已经尝试了我在研究中发现的一切。self.destroy只会创建一个空白窗口。self.grid.destroy返回函数没有destroy属性的错误。我已经尝试将网格的子项设置为self中的所有全局变量,但我无法正确迭代月份,因此设置是永久性的,但我觉得我缺少了一些简单的东西,比如刷新网格并根据更新的月份重新打印
你能给我指出正确的方向或纠正我遗漏的错误吗
下面是整个程序
from Tkinter import *
from calendar import *
import datetime
class Application(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.grid()
DateNow = datetime.datetime.now()
self.year = DateNow.year#declaring global variable year
self.month = DateNow.month#declaring global variable month
self.curr_month()
def curr_month(self):
try:#iterating the month and year backward if index is out of range
if self.month == 0:
self.month = 12
trueYear = int(self.year)
self.year = trueYear - 1
except:
pass
try:#iterating month and year forward if index is out of range
if self.month == 13:
self.month = 1
trueYear = int(self.year)
self.year = trueYear + 1
except:
pass
days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
#create labels
self.label = Label(self, text=months[self.month - 1])#displaying month
self.label.grid(row=0, column = 1)
self.label = Label(self, text=self.year)#displaying year
self.label.grid(row=0, column = 6)
try:#displaying previous month
prevMonthBut = Button(self, text=months[self.month-2], command=self.prevMonth)
prevMonthBut.grid(row=0,column=0)
except:#USED ONLY IF PREVIOUS MONTH IS IN PREVIOUS YEAR
prevMonthBut = Button(self, text=months[11], command=self.prevMonth)
prevMonthBut.grid(row=0,column=0)
try:#displaying next month
nextMonthBut = Button(self, text=months[self.month], command=self.nextMonth)
nextMonthBut.grid(row=0,column=2)
except:#USED ONLY IF NEXT MONTH IS IN NEXT YEAR
nextMonthBut = Button(self, text=months[0], command=self.nextMonth)
nextMonthBut.grid(row=0,column=2)
for i in range(7):
self.label = Label(self, text=days[i])
self.label.grid(row = 1, column = i)
weekday, numDays = monthrange(self.year, self.month)
week = 2
for i in range(1, numDays + 1):
self.button = Button(self, text = str(i))
self.button.grid(row = week, column = weekday)
weekday += 1
if weekday > 6:
week += 1
weekday = 0
def prevMonth(self):
try:
self.grid_forget()
#SHOULD REFRESH THE WINDOW SO BUTTONS DONT OVERLAP
print "forgeting"
except:
print "passed the forgetting"
pass
lastMonth = self.month - 1
self.month = lastMonth
self.curr_month()
def nextMonth(self):
try:
self.grid_forget()
#SHOULD REFRESH THE WINDOW SO BUTTONS DONT OVERLAP
print "forgeting"
except:
print "passed the forgetting"
pass
nextMonth = self.month + 1
self.month = nextMonth
self.curr_month()
mainWindow = Tk()
obj = Application()
mainWindow.mainloop()here
特金特相当有效率。对于您拥有的小部件的数量,最初创建它们不会对性能产生太大影响。下面是一个示例,它的工作原理与您试图做的类似
from calendar import *
import datetime
try:
from tkinter import * # Python 3.x
except:
from Tkinter import * # Python 2.x
class Application(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.grid(row=0, column=0, sticky='news')
DateNow = datetime.datetime.now()
month = int(DateNow.month)
year = int(DateNow.year)
self.createDaysOfWeekLabels()
month_name = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
# Create frames and button controls for previous, current and next month.
self.frameList = [] # List that contains the frame objects.
self.buttonList = [] # List that contains the button objects.
amonth = month - 1
for i in range(3):
if amonth < 0:
amonth = 11
year -= 1
elif amonth == 12:
amonth = 0
year += 1
mFrame = Frame(self)
self.createMonth(mFrame, amonth, year)
self.frameList.append(mFrame)
mButton = Button(self, text=month_name[amonth-1])
mButton['command'] = lambda f=mFrame, b=mButton: self.showMonth(f, b)
mButton.grid(row=0, column=i)
# Grid each frame
mFrame.grid(row=2, column=0, columnspan=7, sticky='news')
if (i == 1):
mButton['relief'] = 'flat'
else:
# Remove all but the ith frame. More efficient to remove than forget and configuration is remembered.
mFrame.grid_remove()
self.buttonList.append(mButton)
amonth += 1
# Create year widget at top left of top frame
label = Label(self, text=year)#displaying year
label.grid(row=0, column=6)
def createDaysOfWeekLabels(self):
days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
for i in range(7):
label = Label(self, text=days[i])
label.grid(row = 1, column = i)
def showMonth(self, mFrame, mButton):
# Display all buttons normally
for button in self.buttonList:
button['relief'] = 'raised'
# Set this month's button relief to flat
mButton['relief'] = 'flat'
# Hide all frames
for frame in self.frameList:
frame.grid_remove()
mFrame.grid()
def createMonth(self, mFrame, month, year):
weekday, numDays = monthrange(year, month)
week = 0
for i in range(1, numDays + 1):
button = Button(mFrame, text = str(i), width=3)
button.grid(row = week, column = weekday)
weekday += 1
if weekday > 6:
week += 1
weekday = 0
mainWindow = Tk()
obj = Application(mainWindow)
mainWindow.mainloop()
这是建议答案的一个修改版本,其中还包括最初的预期意图,即允许用户循环几个月,并将增加一年
from calendar import *
import datetime
try:
from tkinter import * # Python 3.x
except:
from Tkinter import * # Python 2.x
class Application(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.grid(row=0, column=0, sticky='news')
DateNow = datetime.datetime.now()
self.month = int(DateNow.month)
self.year = int(DateNow.year)
self.createDaysOfWeekLabels()
# Create frames and button controls for previous, current and next month.
self.frameList = [] # List that contains the frame objects.
self.buttonList = [] # List that contains the button objects.
self.split()
def split(self):
month_name = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
leftArrow = Button(self, text="<", command=self.prevMonth)
leftArrow.grid(row = 0, column = 0)
rightArrow = Button(self, text=">", command=self.nextMonth)
rightArrow.grid(row = 0, column = 1)
for i in range(3):
try:
print i, "this is i"
print self.month
mFrame = Frame(self)
self.createMonth(mFrame)
self.frameList.append(mFrame)
mButton = Button(self, text=month_name[self.month-1])
mButton['command'] = lambda f=mFrame, b=mButton: self.showMonth(f, b)
mButton.grid(row=1, column=i)
# Grid each frame
mFrame.grid(row=3, column=0, columnspan=7, sticky='news')
if (i == 1):
mButton['relief'] = 'flat'
else:
mButton.grid_remove()
# Remove all but the ith frame. More efficient to remove than forget and configuration is remembered.
mFrame.grid_remove()
self.buttonList.append(mButton)
except:
pass
# Create year widget at top right of top frame
label = Label(self, text=self.year)#displaying year
label.grid(row=0, column=6)
print "-------------------"
def prevMonth(self):
self.month -= 1
print self.month, "this is month in PREV"
if self.month <= 0:
self.month = 12
print self.month, "month inside forinif in PREVMONTH"
self.year -= 1
elif self.month >= 13:
self.month = 0
print self.month, "month inside forinelif in PREVMONTH"
self.year += 1
self.split()
def nextMonth(self):
self.month += 1
print self.month, "this is month in NEXT"
for frame in self.frameList:
frame.grid_remove()
if self.month <= -1:
self.month = 11
print self.month, "month inside forinif in NEXTMONTH"
self.year -= 1
elif self.month >= 13:
self.month = 1
print self.month, "month inside forinelif in NEXTMONTH"
self.year += 1
self.split()
def createDaysOfWeekLabels(self):
days = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun']
for i in range(7):
label = Label(self, text=days[i], width = 3)
label.grid(row = 2, column = i)
def showMonth(self, mFrame, mButton):
# Display all buttons normally
for button in self.buttonList:
button['relief'] = 'raised'
# Set this month's button relief to flat
mButton['relief'] = 'flat'
# Hide all frames
for mframe in self.frameList:
mframe.grid_remove()
mFrame.grid()
def createMonth(self, mFrame):
weekday, numDays = monthrange(self.year, self.month)
week = 0
for i in range(1, numDays + 1):
button = Button(mFrame, text = str(i), width=3)
button.grid(row = week, column = weekday)
weekday += 1
if weekday > 6:
week += 1
weekday = 0
mainWindow = Tk()
obj = Application(mainWindow)
mainWindow.mainloop()
您只创建了一个帧。一旦您忘记了它,主窗口上就不再有GUI元素了。如果您继续在应用程序初始化期间构建GUI组件,然后隐藏/显示框架,那么您将通过init方法创建所有三个框架。然后你忘记了先前可见的帧,并对下一帧或上一帧进行网格化。我试图避免制作3个不同的窗口,而只是在用户循环使用tkinter时循环使用主窗口。。。我没有使用太多tkinter,所以我甚至不确定我是否正确使用了grid\u忘记self.destroy只创建了一个空白窗口-假设self是一个小部件,这是不可能的。销毁无法创建小部件。当我说创建时,我的意思是它会使窗口变为空白并抛出错误。这几乎是完美的!唯一的问题是你只有3个月的时间可以查看。。。对于此日历的最终结果,它必须能够根据需要在月份和年份之间循环,因为此应用程序的最终结果将是一个财务/票据跟踪器,并且3个月的跟踪有点有限。很容易将其扩展到所有12个月。只需增加init部分中的循环,以创建12个按钮和框架,而不是3个。这并不是我想要的,但你给了我修改解决方案所需的东西。对于UI的流动性,我希望保留3个月,并且只需要3个按钮就可以循环使用。因此,你从3月开始,2月和4月为上个月和下个月,当你从这两个月中选择一个月时,它们会转移到中心月,并相应地调整上个月和下个月。