【问题标题】:tkinter labels going off the screen. anyway to detect thistkinter 标签离开屏幕。无论如何要检测到这一点
【发布时间】:2017-05-31 16:11:27
【问题描述】:

我有一些 python 代码使用循环将 tkinter 标签放在有问题的画布上。我的问题是,循环打印的数组是否打印 12 个标签,有时它们适合屏幕,有时如果标签包含大文本,则不适合。

如果屏幕宽度已经耗尽,有没有聪明的方法来打破这个循环

l_row_start_display=6 
for l in G_DATA_VIEW_LABELS_ARRAY: ## list of lists of labels
      l_cnt=0
      for lab in l:
         l_align='W'             
         lab.grid(row=l_row_start_display,
                column=l_cnt,sticky=l_align) 
         l_cnt+=1
      l_row_start_display+=1

或任何其他想法

谢谢

【问题讨论】:

  • 我已经更新了我的答案,包括 2 个示例,说明如何获得接近您想要的东西。一个使用.grid(),另一个使用.place()

标签: python tkinter grid label


【解决方案1】:

编辑:

我找到了一种方法来做到这一点,同时仍然使用.grid() 来放置标签。我们可以在 man 窗口中使用一个框架,然后使用 winfo_width()winfo_height() 获取框架的大小。使用这些信息并在制作每个标签后获取框架的高度和宽度,我们就可以决定何时结束 while 语句。这将在放置标签时为我们提供大致的准确性。唯一的问题是它会测量当前的帧大小而不是小部件的大小,因此您可能需要使用数字才能将其到达您想要的位置。

示例如下:

from tkinter import *

root = Tk()
root.geometry("500x300")

l = ["SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT"]
screen = root.winfo_width()
my_frame = Frame(root)
my_frame.pack(expand=True)

last_row = 0
last_column = 0
my_frame_x = my_frame.winfo_width()
my_frame_y = my_frame.winfo_height()
b = True
while b == True:
    for stuff in l:
        if my_frame_x > 450 or my_frame_y > 250:
            print ("Labels cannot be outside of window!")
            b = False
        else:
            lablabel = Label(my_frame) 
            lablabel.config(text = stuff)         
            lablabel.grid(row = last_row, column = last_column)
            last_row += 1
            last_column += 1
            my_frame.update()
            my_frame_x = my_frame.winfo_width()
            my_frame_y = my_frame.winfo_height()

root.mainloop()

您也可以使用.place() 布局管理器来执行此操作。您需要做的就是定义您希望创建标签的最大像素 x 和 y。

例如,我有一个设置为 800x300 的窗口,并且我已将标签生成器配置为在达到像素限制后不再创建任何标签。这是通过定义标签的像素大小,将该大小添加到下一个位置,然后检查以确保新的 x 和 y 数字不超过您的预定义大小来完成的。

看看这个例子:

from tkinter import *

root = Tk()
root.geometry("800x300")
root.minsize(800, 300)


l = ["SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT", "SOME TEXT"]
last_x = 0
last_y = 0
b = True
while b:
    for stuff in l: 
        last_x+=100
        last_y+=30
        if last_x > 700 or last_y > 270:
            b = False
            print ("Labels cannot be outside of window!")

        else:
            lablabel = Label(root) 
            lablabel.config(text = stuff)         
            lablabel.place(x = last_x, y = last_y, width = 100) 

root.mainloop()

【讨论】:

  • 感谢您的回复。由于标签文本的动态特性,宽度未知。这就是为什么我不能这样做。
  • @Ab Bennett:我环顾四周,找不到任何可以“检测”可见窗口之外的任何东西。我能想到的最接近的方法是测量框架,直到框架变得大于定义的大小。因为框架将扩展直到它与父窗口的大小匹配,您可以以这种方式使用它。但除此之外,我不确定你是否可以做你想做的事。
  • @Ab Bennett:如果你能找到答案,我很想知道 :)
【解决方案2】:

我修改了 Ron Norris 的回复并想出了这个。该函数不断向字符串添加字符,直到达到其最大宽度。它使用分配给小部件的字体来计算字符串的宽度(以像素为单位),然后再将其与小部件的宽度进行比较。

def clip_string(widget, string, offset=0, suffix=''):
    max_w = widget.winfo_width() # max width in pixels
    max_w += offset # adjust for offset
    max_w -= (widget['bd']*2) # substract the borderwidth
    font = tkFont.Font(widget, widget.cget("font")) # get widget's font
    new_string = ''
    for char in range(0,len(string)): # add characters until string is at max
        new_string += string[char] # add character
        str_pixels = font.measure(new_string + suffix, widget)
        if str_pixels > (max_w):
            string = new_string + suffix
            break
    return string

这是一个快速演示。调整“Entry”小部件的宽度,字符串将相应地剪辑。

请注意,我们正在导入 tkinter.font

from tkinter import *
import tkinter.font as tkFont

def clip_string(widget, string, offset=0, suffix=''):
    max_w = widget.winfo_width() # Gax width in pixels
    max_w += offset # Adjust for offset
    max_w -= (widget['bd']*2) # Substract the borderwidth
    font = tkFont.Font(widget, widget.cget("font")) # Get widget's font
    new_string = ''
    for char in range(0,len(string)): # add chars until string is at max
        new_string += string[char] # add character
        str_pixels = font.measure(new_string + suffix, widget) # Measure
        if str_pixels > max_w:
            string = new_string + suffix
            break
    return string

root = Tk()
root.geometry('375x90')

# Create 'Entry' widget
display_txt = StringVar()
entry_widget = Entry(root,
                    textvariable = display_txt,
                    bd = 7 # borderwidth is taken into account
                    )
entry_widget.place(x=30,y=30, width=300, height=35) # try changing the width
entry_widget.update_idletasks() # needs to update to get real size

string = "this is my really long string so let's see where it gets cut off"
clipped_string = clip_string(
                            widget = entry_widget, # Widget to measure
                            string = string, # Our long string
                            offset = -12, # Offset in pixels
                            suffix = '..' # Chars we want to add
                             )
display_txt.set(clipped_string) # set the new string

root.mainloop()

【讨论】:

    【解决方案3】:

    测量字体是关键。

    import tkinter.font
    from tkinter import *
    
    root = Tk()
    # Get a font object
    font_obj = tkinter.font.Font()
    canvas = Canvas(root)
    canvas.grid()
    string_list = []
    string_list.append('the text that is too wide for the canvas and I need to know that it is')
    string_list.append('this text will fit')
    
    # Iterate through the strings, getting the number of pixels it takes.
    # Note that this can be configured larger or smaller based on need.
    can_width = int(canvas['width'])
    i = 0
    for s in string_list:
        str_pixels = font_obj.measure(s, canvas)
        # Compare the width of the canvas to the number of str_pixels
        if str_pixels <= can_width:
            y = (i + 1) * 20
            canvas.create_text(10,y,anchor='nw',text=s,font='TkDefault')
            i += 1
        else:
            # Print a warning, ignore, whatever when the string is too long.
            print("'" + s + "'", "is too long to display in canvas")
    
    root.mainloop()
    

    【讨论】:

    • 此代码出错。 _tkinter.TclError: bad window path name "TkDefault"请提供功能代码。
    猜你喜欢
    • 2010-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-02
    • 1970-01-01
    • 2014-06-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多