PythonTkinter如何计算字符数量可以在扩展标签中显示?

2024-06-26 13:55:21 发布

您现在位置:Python中文网/ 问答频道 /正文

我的窗户上有一些小部件。标签lb3随着我的窗口展开。我想把长数组中的一些字符放在那里。所以,如果窗口很大,一定有更多的字符,如果它的大小变小,那么字符就更少。 因此我需要知道标签的当前高度和宽度(以字符为单位)。 我的问题有一个例子:

import Tkinter as tk
import tkFont
import sys
import os    

last_event_H = 0
last_event_W = 0
LONG_ARRAY = ''

# when window sized
def sizing(event):
    global last_event_H
    global last_event_W
    global LONG_ARRAY
    if (event.width == last_event_W and event.height == last_event_H):
        return
    last_event_H = event.height
    last_event_W = event.width

    width_in_chars = lb3['width']
    height_in_chars = lb3['height']
    first_shown = int(lb1_text.get())
    lb3_text.set(LONG_ARRAY[first_shown:first_shown + width_in_chars * height_in_chars])
    lb2_text.set(LONG_ARRAY[first_shown + width_in_chars * height_in_chars] + ' ...')

class WrappingLabel(tk.Label):
    '''a type of Label that automatically adjusts the wrap to the size'''
    def __init__(self, master=None, **kwargs):
        tk.Label.__init__(self, master, **kwargs)
        self.bind('<Configure>', lambda e: self.config(wraplength=self.winfo_width()))

if __name__ == '__main__':
    root = tk.Tk()
    root.geometry("1280x640")
    dFont=tkFont.Font(family="Arial", size=30) # fixed Font
    LONG_ARRAY = 'a' * 100000 # of symbols

    tb_date = tk.Entry(root, font=dFont)
    tb_date.grid(column=0, row=0, columnspan=3, sticky=tk.NSEW)
    bt_find = tk.Button(root, text="...", font=dFont)
    bt_find.grid(column=9, row=0, columnspan=2, sticky=tk.NSEW)

    lb1_text = tk.StringVar()
    lb1_text.set("1")
    lb1 = tk.Label(root, textvariable=lb1_text, width=10, font=dFont, anchor=tk.NW)
    lb1.grid(column=0, row=1, sticky=tk.NSEW)

    lb2_text = tk.StringVar()
    lb2 = tk.Label(root, textvariable=lb2_text, width=10, font=dFont, anchor=tk.NW)
    lb2.grid(column=1, row=10, columnspan=9, sticky=tk.NSEW)

    lb3_text = tk.StringVar()
    lb3 = WrappingLabel(root, textvariable=lb3_text, font=dFont, anchor=tk.NW, justify=tk.LEFT)
    lb3.grid(column=1, row=1, columnspan=9, rowspan=9, sticky=tk.NSEW)

    for x in range(11):
      tk.Grid.columnconfigure(root, x, weight=1)
    for y in range(11):
      tk.Grid.rowconfigure(root, y, weight=1)
    root.bind("<Configure>", sizing)

    width_in_chars = lb3['width']
    height_in_chars = lb3['height']
    print width_in_chars, height_in_chars # !!!!!!!!!!!!!
    print "-------"
    lb3_text.set(LONG_ARRAY[:width_in_chars * height_in_chars])
    lb2_text.set(LONG_ARRAY[width_in_chars * height_in_chars] + ' ...') # last shown character
    root.mainloop()

lb3的width和height成员现在设置为0。 因为它可以扩展。还有别的办法吗?在


Tags: textineventrootwidtharraylongtk
2条回答

如果你想知道有多少字符可以容纳,首先要做的是得到标签的大小。这需要在显示小部件后进行,因为在显示之前无法知道其宽度。您可以通过调用winfo_reqwidth来预先执行此操作,尽管根据您为packplace或{}使用的选项,该数字可能会大于或小于实际宽度。在

一旦知道了最大大小,就可以使用font对象的font_measure方法来计算字符串中的像素数。然后,只需编写一个循环即可计算出可容纳的最大字符数。在

下面是一个演示如何为过长的标签动态添加“…”的示例:https://stackoverflow.com/a/51144251/7432

感谢@BryanOakley提供的有用链接

我的解决方案如下 (如果有人能做得更好,请回答)

import Tkinter as tk
import tkFont
import sys
import os
import bisect

LONG_ARRAY = ''

class KeyList(object):
    # bisect doesn't accept a key function, so we build the key into our sequence.
    def __init__(self, l, key):
        self.l = l
        self.key = key
    def __len__(self):
        return len(self.l)
    def __getitem__(self, index):
        return self.key(self.l[index], index)

class WrappingLabel(tk.Label):
    '''a type of Label that automatically adjusts the wrap to the size'''
    def __init__(self, master=None, **kwargs):
        tk.Label.__init__(self, master, **kwargs)
        self.bind('<Configure>', self.fit)
        if (not hasattr(self, "original_text")):
            # preserve the original text so we can restore it if the widget grows.
            self.original_text = self["text"]
        self.font = tkFont.nametofont(self["font"])
        self.font_height = 48.88 # self.font.metrics('linespace')

    def fit(self, event):
        max_width = event.width
        max_height = event.height / self.font_height # rough n_lines
        text = LONG_ARRAY[:2000] # TODO !!! self.original_text
        actual_width = self.font.measure(text)
        if (actual_width  > max_width * max_height):
            # the original text won't fit. Keep shrinking until it does
            i = bisect.bisect_left(KeyList(text, key=lambda x,i: self.font.measure(text[:i]+ '...')), max_width * max_height)
            lb3_text.set(text[:i] + '...') # TODO !!! self.original_text
        return self.config(wraplength=self.winfo_width())

if __name__ == '__main__':
    root = tk.Tk()
    root.geometry("1280x640")
    dFont=tkFont.Font(family="Arial", size=30) # fixed Font
    LONG_ARRAY = 'a' * 100000 # of symbols

    root.grid_columnconfigure(0, weight=1)
    frame = tk.Frame(root)
    tk.Grid.rowconfigure(root, 0, weight=1)
    tk.Grid.columnconfigure(root, 0, weight=1)
    frame.grid(row=0, column=0, sticky=tk.NSEW)

    tb_date = tk.Entry(frame, font=dFont)
    tb_date.grid(column=0, row=0, columnspan=3, sticky=tk.NSEW)
    bt_find = tk.Button(frame, text="...", font=dFont)
    bt_find.grid(column=9, row=0, columnspan=2, sticky=tk.NSEW)

    lb1_text = tk.StringVar()
    lb1_text.set("1")
    lb1 = tk.Label(frame, textvariable=lb1_text, width=10, font=dFont, anchor=tk.NW)
    lb1.grid(column=0, row=1, sticky=tk.NSEW)

    lb3_text = tk.StringVar() 
    lb3 = WrappingLabel(frame, textvariable=lb3_text, font=dFont, anchor=tk.NW, justify=tk.LEFT)
    #lb3 = tk.Text(frame, font=dFont, state=tk.DISABLED, wrap=tk.CHAR) # bg=frame["bg"], fg='black', 
    lb3.grid(column=1, row=1, rowspan=2, columnspan=9, sticky=tk.NSEW)

    lb2_text = tk.StringVar()
    lb2 = tk.Label(frame, textvariable=lb2_text, width=10, font=dFont, anchor=tk.NW)
    lb2.grid(column=1, row=4, columnspan=9, rowspan=2, sticky=tk.NSEW)
    lb2_text.set('................................................')

    for y in range(11):
        tk.Grid.columnconfigure(frame, y, weight=1)
    for x in range(5):
        tk.Grid.rowconfigure(frame, x, weight=1)
    lb3_text.set(LONG_ARRAY[:2000])
    #lb3.insert(tk.INSERT, LONG_ARRAY[:2000])
    #lb3.insert(tk.END, "")
    root.mainloop()

相关问题 更多 >