如何修复最近的标签在使用滚动条时被切断 Python Tkinter

How to fix most recent Label gets cut off Python Tkinter when using scrollbar

所以我正在为我的 TCP 聊天制作一个聊天图形用户界面,我想使用一个滚动条,这样无论消息有多长,你都可以看到消息。所以我正在测试一些东西并让它在大多数情况下工作。唯一的问题是填充可视框架后的最新消息被截断了。然后,无论您是否一直向下滚动,每条最近的消息都会被截断。

这是在我多输入了 1 条消息之后(注意滚动条仍然处于禁用状态)

在这里,我将 window 向下拉伸,这样您就可以看到标签就在那里,只是滚动条没有针对该标签进行更新

from tkinter import *
from tkinter.ttk import Combobox
from tkinter import messagebox
from time import sleep

w = Tk()
w.title('Title')
w.geometry('500x400')
w.resizable(width=False, height=False)

def send():
    if send_entry.get() != '':
        messages.append(send_entry.get())
        i = 0
        for msg in messages:
            Label(chat_frame, text=f'User: {msg}').grid(column=0, row=i, padx=10, sticky=W)
            i += 1
        canvas.configure(scrollregion=canvas.bbox("all"))
        send_entry.delete(0, 'end')

def sendEvent(event):
    if send_entry.get() != '':
        messages.append(send_entry.get())
        i = 0
        for msg in messages:
            Label(chat_frame, text=f'User: {msg}').grid(column=0, row=i, padx=10, sticky=W)
            i += 1
        canvas.configure(scrollregion=canvas.bbox("all"))
        send_entry.delete(0, 'end')

messages = []

main_frame = Frame(w)
main_frame.pack(fill=BOTH, expand=1, pady=10)

canvas = Canvas(main_frame)
canvas.pack(side=LEFT, fill=BOTH, expand=1, pady=10)

scrollbar = Scrollbar(main_frame, orient=VERTICAL, command=canvas.yview)
scrollbar.pack(side=RIGHT, fill=Y)

canvas.configure(yscrollcommand=scrollbar.set)
canvas.bind('<Configure>', lambda e: canvas.configure(scrollregion=canvas.bbox("all")))

chat_frame = Frame(canvas)
canvas.create_window((0, 0), window=chat_frame, anchor=NW)

bot_frame = Frame(w).pack(side=BOTTOM)

send_entry = Entry(bot_frame, width=55)
send_entry.pack(side=LEFT, padx=30, pady=10)
send_button = Button(bot_frame, text='Send', command=send).pack(side=LEFT)

w.bind('<Return>', sendEvent)

w.mainloop()

首先,您应该将 <Configure> 绑定到 chat_frame 而不是 canvas。其次,您需要在更新 scrollregion 选项之前更新 canvas。

您也可以组合使用 send()sendEvent(),因为它们的作用相同。并且不要在每次添加新消息时都创建新的标签集,只需为新添加的消息创建一个新标签即可。

from tkinter import *
from tkinter.ttk import Combobox
#from tkinter import messagebox
#from time import sleep

w = Tk()
w.title('Title')
w.geometry('500x400')
w.resizable(width=False, height=False)

def send(event=None):
    msg = send_entry.get().strip()
    if msg != '':
        messages.append(msg)
        Label(chat_frame, text=f"User: {msg}").grid(padx=10, sticky=W)
        send_entry.delete(0, 'end')
        # make the last message visible
        canvas.update()
        canvas.yview_moveto(1)

messages = []

main_frame = Frame(w)
main_frame.pack(fill=BOTH, expand=1, pady=10)

canvas = Canvas(main_frame)
canvas.pack(side=LEFT, fill=BOTH, expand=1, pady=10)

scrollbar = Scrollbar(main_frame, orient=VERTICAL, command=canvas.yview)
scrollbar.pack(side=RIGHT, fill=Y)

canvas.configure(yscrollcommand=scrollbar.set)
#canvas.bind('<Configure>', lambda e: canvas.configure(scrollregion=canvas.bbox("all")))

chat_frame = Frame(canvas)
canvas.create_window((0, 0), window=chat_frame, anchor=NW)
chat_frame.bind('<Configure>', lambda e: canvas.configure(scrollregion=canvas.bbox("all")))

bot_frame = Frame(w)
bot_frame.pack(side=BOTTOM)

send_entry = Entry(bot_frame, width=55)
send_entry.pack(side=LEFT, padx=30, pady=10)

Button(bot_frame, text='Send', command=send).pack(side=LEFT)

w.bind('<Return>', send)

w.mainloop()

不过,最好使用 ScrolledText 小部件代替聊天消息框。