Python tkinter with ttk calendar -


i using this code create simple calendar on tkinter. when put calendar on main root window, calendar appear fine. so, decided put button create tkinter toplevel window , put 1 more calendar on toplevel window.but time failed display calendar , instead gave me error," tclerror: can't pack .18913120 inside .18912200.18912400". explain why getting error message.

this sample code:

import calendar import sys try:     import tkinter     import tkfont except importerror: # py3k     import tkinter tkinter     import tkinter.font tkfont  import ttk  def get_calendar(locale, fwday):     # instantiate proper calendar class     if locale none:         return calendar.textcalendar(fwday)     else:         return calendar.localetextcalendar(fwday, locale)  class calendar(ttk.frame):     # xxx todo: cget , configure      datetime = calendar.datetime.datetime     timedelta = calendar.datetime.timedelta      def __init__(self, master=none, **kw):         """         widget-specific options          locale, firstweekday, year, month, selectbackground,         selectforeground         """         # remove custom options kw before initializating ttk.frame         fwday = kw.pop('firstweekday', calendar.monday)         year = kw.pop('year', self.datetime.now().year)         month = kw.pop('month', self.datetime.now().month)         locale = kw.pop('locale', none)         sel_bg = kw.pop('selectbackground', '#ecffc4')         sel_fg = kw.pop('selectforeground', '#05640e')          self._date = self.datetime(year, month, 1)         self._selection = none # no date selected          ttk.frame.__init__(self, master, **kw)          self._cal = get_calendar(locale, fwday)          self.__setup_styles()       # creates custom styles         self.__place_widgets()      # pack/grid used widgets         self.__config_calendar()    # adjust calendar columns , setup tags         # configure canvas, , proper bindings, selecting dates         self.__setup_selection(sel_bg, sel_fg)          # store items ids, used insertion later         self._items = [self._calendar.insert('', 'end', values='')                             _ in range(6)]         # insert dates in empty calendar         self._build_calendar()          # set minimal size widget         self._calendar.bind('<map>', self.__minsize)      def __setitem__(self, item, value):         if item in ('year', 'month'):             raise attributeerror("attribute '%s' not writeable" % item)         elif item == 'selectbackground':             self._canvas['background'] = value         elif item == 'selectforeground':             self._canvas.itemconfigure(self._canvas.text, item=value)         else:             ttk.frame.__setitem__(self, item, value)      def __getitem__(self, item):         if item in ('year', 'month'):             return getattr(self._date, item)         elif item == 'selectbackground':             return self._canvas['background']         elif item == 'selectforeground':             return self._canvas.itemcget(self._canvas.text, 'fill')         else:             r = ttk.tclobjs_to_py({item: ttk.frame.__getitem__(self, item)})             return r[item]      def __setup_styles(self):         # custom ttk styles         style = ttk.style(self.master)         arrow_layout = lambda dir: (             [('button.focus', {'children': [('button.%sarrow' % dir, none)]})]         )         style.layout('l.tbutton', arrow_layout('left'))         style.layout('r.tbutton', arrow_layout('right'))      def __place_widgets(self):         # header frame , widgets         hframe = ttk.frame(self)         lbtn = ttk.button(hframe, style='l.tbutton', command=self._prev_month)         rbtn = ttk.button(hframe, style='r.tbutton', command=self._next_month)         self._header = ttk.label(hframe, width=15, anchor='center')         # calendar         self._calendar = ttk.treeview(show='', selectmode='none', height=7)          # pack widgets         hframe.pack(in_=self, side='top', pady=4, anchor='center')         lbtn.grid(in_=hframe)         self._header.grid(in_=hframe, column=1, row=0, padx=12)         rbtn.grid(in_=hframe, column=2, row=0)         self._calendar.pack(in_=self, expand=1, fill='both', side='bottom')      def __config_calendar(self):         cols = self._cal.formatweekheader(3).split()         self._calendar['columns'] = cols         self._calendar.tag_configure('header', background='grey90')         self._calendar.insert('', 'end', values=cols, tag='header')         # adjust columns width         font = tkfont.font()         maxwidth = max(font.measure(col) col in cols)         col in cols:             self._calendar.column(col, width=maxwidth, minwidth=maxwidth,                 anchor='e')      def __setup_selection(self, sel_bg, sel_fg):         self._font = tkfont.font()         self._canvas = canvas = tkinter.canvas(self._calendar,             background=sel_bg, borderwidth=0, highlightthickness=0)         canvas.text = canvas.create_text(0, 0, fill=sel_fg, anchor='w')          canvas.bind('<buttonpress-1>', lambda evt: canvas.place_forget())         self._calendar.bind('<configure>', lambda evt: canvas.place_forget())         self._calendar.bind('<buttonpress-1>', self._pressed)      def __minsize(self, evt):         width, height = self._calendar.master.geometry().split('x')         height = height[:height.index('+')]         self._calendar.master.minsize(width, height)      def _build_calendar(self):         year, month = self._date.year, self._date.month          # update header text (month, year)         header = self._cal.formatmonthname(year, month, 0)         self._header['text'] = header.title()          # update calendar shown dates         cal = self._cal.monthdayscalendar(year, month)         indx, item in enumerate(self._items):             week = cal[indx] if indx < len(cal) else []             fmt_week = [('%02d' % day) if day else '' day in week]             self._calendar.item(item, values=fmt_week)      def _show_selection(self, text, bbox):         """configure canvas new selection."""         x, y, width, height = bbox          textw = self._font.measure(text)          canvas = self._canvas         canvas.configure(width=width, height=height)         canvas.coords(canvas.text, width - textw, height / 2 - 1)         canvas.itemconfigure(canvas.text, text=text)         canvas.place(in_=self._calendar, x=x, y=y)      # callbacks      def _pressed(self, evt):         """clicked somewhere in calendar."""         x, y, widget = evt.x, evt.y, evt.widget         item = widget.identify_row(y)         column = widget.identify_column(x)          if not column or not item in self._items:             # clicked in weekdays row or outside columns             return          item_values = widget.item(item)['values']         if not len(item_values): # row empty month             return          text = item_values[int(column[1]) - 1]         if not text: # date empty             return          bbox = widget.bbox(item, column)         if not bbox: # calendar not visible yet             return          # update , show selection         text = '%02d' % text         self._selection = (text, item, column)         self._show_selection(text, bbox)      def _prev_month(self):         """updated calendar show previous month."""         self._canvas.place_forget()          self._date = self._date - self.timedelta(days=1)         self._date = self.datetime(self._date.year, self._date.month, 1)         self._build_calendar() # reconstuct calendar      def _next_month(self):         """update calendar show next month."""         self._canvas.place_forget()          year, month = self._date.year, self._date.month         self._date = self._date + self.timedelta(             days=calendar.monthrange(year, month)[1] + 1)         self._date = self.datetime(self._date.year, self._date.month, 1)         self._build_calendar() # reconstruct calendar      # properties      @property     def selection(self):         """return datetime representing current selected date."""         if not self._selection:             return none          year, month = self._date.year, self._date.month         return self.datetime(year, month, int(self._selection[0]))   def myfunction():     root2=tkinter.toplevel(root)     ttkcal = calendar(root2,firstweekday=calendar.sunday)     ttkcal.pack(expand=1, fill='both')  root=tkinter.tk()  frame=tkinter.frame(root) frame.pack(side="left")  button=tkinter.button(root,text="top level",command=myfunction) button.pack(side="right")  ttkcal = calendar(frame,firstweekday=calendar.sunday) ttkcal.pack(expand=1, fill='both') root.mainloop() 

author of widget used 1 unnecessary action: widget set minimal size of root window, , assumed window in program (it isn't bug, it's feature).

1.in method def __place_widgets(self):

self._calendar = ttk.treeview(show='', selectmode='none', height=7) 

should be:

self._calendar = ttk.treeview(self, show='', selectmode='none', height=7) 

2.in constructor remove line:

self._calendar.bind('<map>', self.__minsize) 

3.delete __minsize method
4.if want set minimal size root2 use code:

def myfunction():     root2=tkinter.toplevel(root)     ttkcal = calendar(root2,firstweekday=calendar.sunday)     ttkcal.pack(expand=1, fill='both')     root2.update()     root2.minsize(root2.winfo_reqwidth(), root2.winfo_reqheight()) 

Comments

Popular posts from this blog

linux - xterm copying to CLIPBOARD using copy-selection causes automatic updating of CLIPBOARD upon mouse selection -

c++ - qgraphicsview horizontal scrolling always has a vertical delta -