如何修复最近的标签在使用滚动条时被切断 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
小部件代替聊天消息框。
所以我正在为我的 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
小部件代替聊天消息框。