2014-11-16 28 views
5

Tôi đang sử dụng ttkcalendar.py có thể tìm thấy in this link.ttk.Treeview - Không thể thay đổi chiều cao hàng

Tôi đã thích nghi để sử dụng trong Python 3.3

Về cơ bản những gì tôi đang cố gắng làm là nhập widget lịch này vào ứng dụng Tkinter của tôi, hoạt động tốt và không có vấn đề gì ở đó.

Những vấn đề tôi muốn vượt qua là:

  1. Làm thế nào để thay đổi kích thước font chữ của lịch (Tháng, Ngày & Ngày) - Hoàn
  2. Làm thế nào để thay đổi ngày đã chọn để nó đi bold. - Đã hoàn tất
  3. Làm cách nào để thay đổi chiều cao của các hàng trong số treeview như trong nỗ lực ưu tiên kích thước phông chữ nhưng chiều cao hàng không tăng với kích thước phông chữ. - TUYỆT VỜI TRỢ GIÚP GIÚP

Xin cảm ơn trước.

EDIT 1:

Tìm dưới mã cho toàn bộ chương trình:

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:

Làm thế nào tôi có thể thay đổi relief của Treeview?

Trả lời

9

Có lẽ giống như bạn, tôi dự kiến ​​các dòng sẽ mở rộng khi cần thiết. Nhưng tôi đã xác nhận vấn đề với mã bên dưới, với giải pháp (hai dòng kiểu) bị bỏ qua. Khi tôi không thể tìm thấy giải pháp here và trang Kiểu tương ứng, tôi đã googled và tìm thấy this. Cuộn xuống câu trả lời của Emiliano và một số điều sau đây (cũng có tùy chọn thụt lề).

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

Ở trên, với câu trả lời bị bỏ qua, là ví dụ về mã tối thiểu thể hiện sự cố. Đây là thứ để đăng!

EDIT 1:

Để làm widget Lịch đúng cách có thể nhập cảng và có thể sử dụng trong ứng dụng khác, nó sẽ sử dụng một kiểu tùy chỉnh, vì vậy phong cách của nó không ảnh hưởng đến bất kỳ treeviews khác trong ứng dụng.

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

EDIT 2:

Tôi chỉ tìm hiểu về phong cách TTK bản thân mình. Để trả lời câu hỏi cứu trợ của bạn, tôi đã truy cập vào số style doc này và thử những điều sau đây trong Idle's Shell sau khi chạy phần trên, với hai sửa đổi trong Chỉnh sửa 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') 
{} 

Tôi không thấy bất kỳ đường viền nào hoặc không thấy bất kỳ ảnh hưởng nào của cài đặt. Có lẽ cứu trợ được áp dụng cho các đường viền giữa các cột. Tôi không biết. (Lưu ý rằng việc thay đổi rowheight có sẵn ngay lập tức, vì vậy cấu hình là 'sống'.)

+0

Cảm ơn Terry! Đã dành nhiều giờ cố gắng tìm ra nó mà không có kết quả. Tôi có một câu hỏi nhỏ cần thêm: Làm thế nào tôi có thể thay đổi sự trợ giúp của Treeview? Có thể không? – MistUnleashed

+0

Xem Chỉnh sửa 2 ở trên. –

+0

Câu trả lời hay, những người tuyệt vời. –

0

Làm thế nào tôi có thể thay đổi chiều cao của các hàng trong treeview như trong prevoius cố gắng kích thước phông chữ có thể tăng lên nhưng chiều cao hàng không tăng với kích thước phông chữ. - vẫn đang chờ TRỢ GIÚP

Trong trường hợp bạn vẫn đang chờ sự giúp đỡ trên thế này, có một way để thay đổi chiều cao hàng, dù rằng các nhóm google chủ đề nói rằng nó không phải là chính thức được hỗ trợ bởi Tk:

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

Tôi thấy rằng đối tượng Phông chữ Tkinter có phương thức metric(), cho chiều cao của nó là "không gian dòng". Cho phép chiều cao hàng để được thu nhỏ tự động:

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} 

Với điều đó, bạn có thể lấy chiều cao font chữ với:

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

Sau đó sử dụng nó để thiết lập các rowheight trong widget Treeview của bạn:

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

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

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

Thay đổi các tham số đối tượng phông chữ thoải mái cập nhật tiện ích con Số lần xem trang, nhưng hàng không được cập nhật và cần được làm lại. Vì vậy, ví dụ, việc đo kích thước phông chữ với một phím tắt có thể trông như thế này:

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) 

Tôi thực sự muốn làm điều tương tự với Control-mousewheel, nhưng không tìm ra hành vi nào được nêu ra (sẽ được vui mừng nghe cách hoạt động).

Hy vọng điều này có ích.

+0

Tuyệt vời !! Chính xác những gì tôi cần. – Riyaz

Các vấn đề liên quan