tkinter grid overlapping

Question:

I am building a calendar that allows the user to cycle through the months and years by pressing the buttons created of the previous month and next month. Essentially what I want the main window to do is update with the new month upon clicking PREV or NEXT month with the correct days, which it does, only issue is the day buttons that display the specific days of the month overlap when cycling through.
Below is the part where I am having issues:

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()

When the program iterates between the months the grid does not refresh it just overlaps the days and months. I have tried EVERYTHING I found in my hours of research. “self.destroy()” merely creates a blank window. “self.grid.destroy()” returns and error that function has no attribute destroy. I have tried making the children of grid all global variables within self and I cant iterate through the months correctly so the set up is permanent but I feel like I am missing something simple as far as working with refreshing the grid and reprinting the based upon the updated month.

Can you please point me in the right direction or correct the error I am missing?

below is the entire program

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
Asked By: nicholas

||

Answers:

Tkinter is fairly efficient. And for the number of widgets that you have, it won’t impact performance much to create them all initially. Here is a sample that works about like what you were trying to do.

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()
Answered By: Ron Norris

This is a modified version of the proposed answer that also includes the original desired intent of allowing the user to cycle through the months and will also increment the year.

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()
Answered By: nicholas

Use something like [yourWidget].grid(row=0, column=0, columnspan=4)

Answered By: Tyler Bowers
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.