Ttk.Treeview - Unable to change row height

I use ttkcalendar.py which can be found at this link.

I adapted it for use in Python 3.3

Basically, what I'm trying to do is inject this calendar widget into my Tkinter application, which works great and there are no problems there.

I want to overcome the problems:

  1. How to change calendar font size (Month, Days, and Dates) - Completed
  2. How to change the selected date so that it bold . - completed
  3. How can I change the row height in treeview as when trying to exceed the font size, you can increase the font size, but the line height does not increase with the font size. - STILL ANOTHER HELP

Thanks in advance.

EDIT 1:

Find the code below for the entire program:

 import calendar import tkinter as Tkinter import tkinter.font as tkFont from tkinter import ttk #Imports ttk Module def get_calendar(locale, fwday): #Instantiate Proper Calendar Class if locale is None: return calendar.TextCalendar(fwday) else: return calendar.LocaleTextCalendar(fwday, locale) class Calendar(ttk.Frame): 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 From 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', '#EEEEEE') sel_fg = kw.pop('selectforeground', '#B6333B') 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 a Canvas & Proper Bindings for Selecting Dates self.__setup_selection(sel_bg, sel_fg) #Store Item ids - Used for Insertion Later On self._items = [self._calendar.insert('', 'end', values='') for _ in range(6)] #Insert Dates in the Currently Empty Calendar self._build_calendar() #Set Minimal Size for Widget self._calendar.bind('<Map>', self.__minsize) def __setitem__(self, item, value): if item in ('year', 'month'): raise AttributeError("attribute '%s' is 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', font='Arial 20') #Main Calendar self._calendar = ttk.Treeview(show='', selectmode='none', height='6') #Pack The 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', font='Arial 20') self._calendar.insert('', 'end', values=cols, tag=('header', 'dayFont')) #Change Font of dayFont TAG self._calendar.tag_configure('dayFont', font='Arial 20') #Adjust Column Widths font = tkFont.Font(size=20) maxwidth = max(font.measure(col) for col in cols) for col in cols: self._calendar.column(col, width=maxwidth, minwidth=maxwidth, anchor='c') def __setup_selection(self, sel_bg, sel_fg): self._font = tkFont.Font() canvas = Tkinter.Canvas(self._calendar, background=sel_bg, borderwidth=0, highlightthickness=0) self._canvas = canvas canvas.text = canvas.create_text(0, 0, fill=sel_fg, anchor='c') 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 Showing Dates cal = self._cal.monthdayscalendar(year, month) for indx, item in enumerate(self._items): week = cal[indx] if indx < len(cal) else [] fmt_week = [('%02d' % day) if day else '' for day in week] self._calendar.item(item, values=fmt_week, tag='bodyFont') self._calendar.tag_configure('bodyFont', font='Arial 10') def _show_selection(self, text, bbox): #SELECTION FONT """Configure canvas for a 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, font='Arial 15 bold') canvas.place(in_=self._calendar, x=x, y=y) #Callbacks def _pressed(self, evt): """Clicked somewhere in the 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 the Weekdays Row or Just Outside The Columns return item_values = widget.item(item)['values'] if not len(item_values): #Row is Empty For This Month return text = item_values[int(column[1]) - 1] if not text: #Date is Empty return bbox = widget.bbox(item, column) if not bbox: #Calendar is not Visible Yet return #Update & Then Show Selection text = '%02d' % text self._selection = (text, item, column) self._show_selection(text, bbox) def _prev_month(self): """Updated calendar to show the 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) #Reconstruct Calendar self._build_calendar() def _next_month(self): """Update calendar to show the 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() #Properties #----------------------------------------------------- @property def selection(self): """Return a datetime representing the 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])) #---------------------------------- 

EDIT 2:

How can I change relief Treeview ?

+6
source share
3 answers

Perhaps, like you, I expected the lines to expand as needed. But I confirmed the problem with the code below, since the solution (two style lines) is omitted. When I could not find the solution here and the corresponding style page, I googled and found this . Scroll down to Emiliano's answer and some of the following (there is also an indent option).

 import tkinter as tk from tkinter import ttk root = tk.Tk() root.geometry('500x200') style = ttk.Style(root) style.configure('Treeview', rowheight=40) #SOLUTION tree = ttk.Treeview(root) tree.insert('', 0, text='Line 1 of many XXX', tags='T') tree.insert('', 1, text='Line 2 of many XXX', tags='T') tree.insert('', 2, text='Line 3 of many XXX', tags='T') tree.column('#0', stretch=True) tree.tag_configure('T', font='Arial 20') tree.pack(fill='x') 

The above, with the answer omitted, is an example of minimal code that shows a problem. This is what you need to publish!

EDIT 1:

In order for the Calendar widget to be correctly imported and used in another application, it must use its own style, so its style does not affect other tree images in the application.

 style.configure('Calendar.Treeview', rowheight=40) tree = ttk.Treeview(root, style='Calendar.Treeview') 

EDIT 2:

I am just learning ttk styles. To answer your question about providing assistance, I went to this doc and skipped the following in the Idle Shell after starting above, with two modifications in Edit 1.

 >>> style.layout('Calendar.Treeview') [('Treeview.field', {'sticky': 'nswe', 'children': [('Treeview.padding', {'sticky': 'nswe', 'children': [('Treeview.treearea', {'sticky': 'nswe'})]})], 'border': '1'})] >>> style.element_options('Calendar.Treeview.border') ('-relief',) >>> style.lookup('Calendar.Treeview.border', 'relief') '' >>> style.configure('Calendar.Treeview.border', relief='raised') {} 

I do not see any border and do not see any tuning effect. Perhaps the help extends to the borders between the columns. I dont know. (Note that changing the lineup is immediately available, so the configuration is live.)

+11
source

I found that the Tkinter font object has a metrics () method that gives its height as "space space". This allows you to dynamically scale the line height:

 try: from tkinter.font import Font from tkinter.ttk import Style, Treeview from tkinter import * except: from tkFont import Font font ttk import Style, Treeview from Tkinter import * font=Font(family='Arial', size=20) font.metrics() #output: {'ascent': 31, 'descent': 7, 'linespace': 38, 'fixed': 0} 

With this, you can get the font height with:

 font.metrics()['linespace'] #output: 38 

Then use it to set the line as a Treeview widget:

 fontheight=font.metrics()['linespace'] style=Style() style.configure('Calendar.Treeview', font=font, rowheight=fontheight) tree=Treeview(style='Calendar.Treeview') 

Changing the parameters of the font object conveniently updates the Treeview widget, but the line is not updated, and it needs to be redone. For example, scaling a font size using a keyboard shortcut might look like this:

 def scaleup(): font['size']+=1 style.configure('Calendar.Treeview', rowheight=font.metrics()['linespace']) def scaledown(): font['size']-=1 style.configure('Calendar.Treeview', rowheight=font.metrics()['linespace']) tree.bind('<Control-equal>', scaleup) tree.bind('<Control-minus>', scaledown) 

I really wanted to do the same with Control-MouseWheel, but I didn’t understand the behavior yet (I would be glad to hear how it works).

Hope this comes in handy.

+4
source

How can I change the height of the lines in the tree structure, since when trying to increase the font size, you can increase it, but the line height does not increase with the font size. - STILL ASSISTING HELP

If you still expect help with this, there is a way to change the line height, although this google groups thread says it is not officially supported by Tk:

 #apply any configuration options ttk.Style().configure('Treeview',rowheight=30) 
+1
source

Source: https://habr.com/ru/post/1206981/


All Articles