简体   繁体   English

ttk.Treeview - 无法更改行高

[英]ttk.Treeview - Can't change row height

I'm using ttkcalendar.py which can be found in this link.我正在使用可以在此链接中找到的ttkcalendar.py

I've adapted it for use in Python 3.3我已经将它改编为在Python 3.3

Basically what i'm trying to do is enter this calendar widget into my Tkinter application, which works fine and there's no problems there.基本上我想要做的是将这个日历小部件输入到我的 Tkinter 应用程序中,它运行良好并且没有问题。

The problems I wish to overcome are:我希望克服的问题是:

  1. How do I change the font size of the calendar (Month,Days & Dates) - Completed如何更改日历的字体大小(月、日和日期) -已完成
  2. How do I change the selected date so it goes bold .如何更改所选日期使其变为bold - Completed -已完成
  3. How can I change the height of the rows in the treeview as in prevoius attempts font size can be increased but the row height does not increase with font size.如何更改treeview中行的高度,因为在以前的尝试中可以增加字体大小,但行高不会随字体大小而增加。 - STILL AWAITING HELP -仍在等待帮助

Thanks in advance.提前致谢。

EDIT 1:编辑 1:

Find below the code for the whole 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:编辑2:

How can I change the relief of the Treeview ?如何更改Treeviewrelief

Perhaps like you, I expected lines to expand as necessary.也许和你一样,我希望线路在必要时扩展。 But I confirmed the problem with the code below, with the solution (the two style lines) 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).向下滚动到 Emiliano 的答案,以及以下一些内容(还有一个缩进选项)。

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 exhibits the problem.以上,省略了答案,是展示问题的最小代码示例。 This is the sort of thing to post!这种东西要发帖!

EDIT 1:编辑 1:

To make the Calendar widget properly importable and usable in another application, it should use a custom style, so its style does not affect any other treeviews in the app.为了使日历小部件可以在另一个应用程序中正确导入和使用,它应该使用自定义样式,因此它的样式不会影响应用程序中的任何其他树视图。

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

EDIT 2:编辑2:

I am just learning about ttk styles myself.我只是自己学习 ttk 样式。 To answer your relief question, I went to this style doc and tried the following in Idle's Shell after running the above, with the two modifications in Edit 1.为了回答您的问题,我转到了这个样式文档,并在运行上述代码后在 Idle's Shell 中尝试了以下内容,并在 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 nor did not see any effect of the setting.我没有看到任何边框,也没有看到设置的任何效果。 Perhaps relief applies to borders between columns.也许救济适用于列之间的边界。 I don't know.我不知道。 (Note that changing rowheight is immediately available, so configuration is 'live'.) (请注意,更改行高是立即可用的,因此配置是“实时”的。)

I found that the Tkinter Font object has a metrics() method, that gives its height as "linespace".我发现 Tkinter Font 对象有一个 metrics() 方法,该方法将其高度设为“linespace”。 That allows the row height to be scaled dynamically:这允许动态缩放行高:

try:
    from tkinter.font import Font
    from tkinter.ttk import Style, Treeview
    from tkinter import *         
except:
    from tkFont import Font
    from 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 that, you can get the font height with:有了这个,你可以得到字体高度:

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

Then use it to set the rowheight in your Treeview widget:然后使用它在 Treeview 小部件中设置行高:

fontheight=font.metrics()['linespace']

style=Style()
style.configure('Calendar.Treeview', font=font, rowheight=fontheight)   

tree=Treeview(style='Calendar.Treeview')

Changing the font object parameters comfortably updates the Treeview widget, but the rowheight doesn't get updated, and needs to be redone.更改字体对象参数可以轻松地更新 Treeview 小部件,但行高不会更新,需要重做。 So for example, scaling the font size with a keyboard shortcut may look like this:例如,使用键盘快捷键缩放字体大小可能如下所示:

def scaleup(event):
    font['size']+=1
    style.configure('Calendar.Treeview', rowheight=font.metrics()['linespace'])

def scaledown(event):
    font['size']-=1
    style.configure('Calendar.Treeview', rowheight=font.metrics()['linespace'])

tree.bind('<Control-equal>', scaleup)
tree.bind('<Control-minus>', scaledown)

I actually wanted to do the same with Control-MouseWheel, but didn't figure out the behavior yet (Would be glad to hear how that works).我实际上想用 Control-MouseWheel 做同样的事情,但还没有弄清楚行为(很高兴听到它是如何工作的)。

Hope this comes handy.希望这能派上用场。

How can I change the height of the rows in the treeview as in prevoius attempts font size can be increased but the row height does not increase with font size.如何更改树视图中行的高度,因为在以前的尝试中可以增加字体大小,但行高不会随字体大小而增加。 - STILL AWAITING HELP - 仍在等待帮助

In case you are still awaiting help on this one, there is a way to change the row height, though that google groups thread says that it isn't officially supported by Tk:在你仍然在等待这一个帮助的情况下,一种方法来改变行的高度,虽然,谷歌组线程说,它不是正式Tk的支持:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM