gpt4 book ai didi

python - 在 Python 的 tkinter 中自动调整大小

转载 作者:行者123 更新时间:2023-11-28 22:05:35 28 4
gpt4 key购买 nike

在下面的方法中,我尝试创建一个框架,将标签和文本小部件放入其中,然后将它们放入另一个文本小部件中。结果有两个问题。应该怎么改成:

  1. 内部文本对象是否根据插入的文本具有正确的高度?
  2. 获取要调整为外部小部件当前尺寸的框架和文本?

建议将不胜感激!让消息按预期出现在代码中有些困难。它们应该在主小部件被拉伸(stretch)时自动换行和调整大小。

def display(self, name, message):
frame = tkinter.ttk.Frame(self.__text, borderwidth=1)
frame.grid_rowconfigure(0, weight=1)
frame.grid_columnconfigure(1, weight=1)
name = tkinter.ttk.Label(frame, text=name)
name.grid(row=0, column=0)
text = tkinter.Text(frame, wrap=tkinter.WORD, height=1)
text.grid(row=0, column=1, sticky=tkinter.EW)
text.insert('1.0', message)
text.configure(state=tkinter.DISABLED)
self.__text.window_create('1.0', window=frame, stretch=tkinter.TRUE)

该代码应该生成一个带有标签的框架以及旁边的文字换行文本。正在显示的每条新消息都应该位于旧消息之上,并且随着消息列表的增长,应该可以滚动和阅读旧消息(无限期)。不幸的是,这并不比上面的代码更好。

def display(self, name, message):
frame = tkinter.ttk.Frame(self.__text, borderwidth=1, relief='solid')
name = tkinter.ttk.Label(frame, text=name)
text = tkinter.Text(frame, wrap=tkinter.WORD, height=1)
frame.pack(expand=tkinter.TRUE, fill=tkinter.BOTH)
name.pack(fill=tkinter.BOTH, side=tkinter.LEFT)
text.pack(expand=tkinter.TRUE, fill=tkinter.BOTH)
text.insert('1.0', message)
text.configure(state=tkinter.DISABLED)
self.__text.window_create('1.0', window=frame)

框架似乎已正确配置,但让外部文本框充当几何管理器并设置内部文本框的高度属性似乎是这里的主要问题。外部文本框当前未调整框架大小,我不确定要根据其中的文本量编写什么代码来调整内部文本框的高度。这是程序的完整代码:

import tkinter
import tkinter.ttk

import datetime
import getpass
import os
import uuid

################################################################################

class DirectoryMonitor:

def __init__(self, path):
self.__path = path
self.__files = {}

def update(self, callback):
for name in os.listdir(self.__path):
if name not in self.__files:
path_name = os.path.join(self.__path, name)
self.__files[name] = FileMonitor(path_name)
errors = set()
for name, monitor in self.__files.items():
try:
monitor.update(callback)
except OSError:
errors.add(name)
for name in errors:
del self.__files[name]


################################################################################

class FileMonitor:

def __init__(self, path):
self.__path = path
self.__modified = 0
self.__position = 0

def update(self, callback):
modified = os.path.getmtime(self.__path)
if modified != self.__modified:
self.__modified = modified
with open(self.__path, 'r') as file:
file.seek(self.__position)
text = file.read()
self.__position = file.tell()
callback(self.__path, text)

################################################################################

class Aggregator:

def __init__(self):
self.__streams = {}

def update(self, path, text):
if path not in self.__streams:
self.__streams[path] = MessageStream()
parts = text.split('\0')
assert not parts[-1], 'Text is not properly terminated!'
self.__streams[path].update(parts[:-1])

def get_messages(self):
all_messages = set()
for stream in self.__streams.values():
all_messages.update(stream.get_messages())
return sorted(all_messages, key=lambda message: message.time)

################################################################################

class MessageStream:

def __init__(self):
self.__name = None
self.__buffer = None
self.__waiting = set()

def update(self, parts):
if self.__name is None:
self.__name = parts.pop(0)
if self.__buffer is not None:
parts.insert(0, self.__buffer)
self.__buffer = None
if len(parts) & 1:
self.__buffer = parts.pop()
for index in range(0, len(parts), 2):
self.__waiting.add(Message(self.__name, *parts[index:index+2]))

def get_messages(self):
messages = self.__waiting
self.__waiting = set()
return messages

################################################################################

class Message:

def __init__(self, name, timestamp, text):
self.name = name
self.time = datetime.datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%SZ')
self.text = text

################################################################################

class MessageWriter:

def __init__(self, path, name):
assert '\0' not in name, 'Name may not have null characters!'
self.__name = str(uuid.uuid1())
self.__path = os.path.join(path, self.__name)
with open(self.__path, 'w') as file:
file.write(name + '\0')

@property
def name(self):
return self.__name

def write(self, text):
assert '\0' not in text, 'Text may not have null characters!'
timestamp = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
with open(self.__path, 'a') as file:
file.write(timestamp + '\0' + text + '\0')

################################################################################

class Logos(tkinter.ttk.Frame):

@classmethod
def main(cls, path):
tkinter.NoDefaultRoot()
root = tkinter.Tk()
root.title('Logos 2.0')
root.minsize(320, 240) # QVGA
view = cls(root, path)
view.grid(row=0, column=0, sticky=tkinter.NSEW)
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root.mainloop()

def __init__(self, master, path, **kw):
super().__init__(master, **kw)
self.configure_widgets()
self.__writer = MessageWriter(path, getpass.getuser())
self.__monitor = DirectoryMonitor(path)
self.__messages = Aggregator()
self.after_idle(self.update)

def configure_widgets(self):
# Create widgets.
self.__text = tkinter.Text(self, state=tkinter.DISABLED)
self.__scroll = tkinter.ttk.Scrollbar(self, orient=tkinter.VERTICAL,
command=self.__text.yview)
self.__entry = tkinter.ttk.Entry(self, cursor='xterm')
# Alter their settings.
self.__text.configure(yscrollcommand=self.__scroll.set)
# Place everything on the grid.
self.__text.grid(row=0, column=0, sticky=tkinter.NSEW)
self.__scroll.grid(row=0, column=1, sticky=tkinter.NS)
self.__entry.grid(row=1, column=0, columnspan=2, sticky=tkinter.EW)
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
# Setup box for typing.
self.__entry.bind('<Control-Key-a>', self.select_all)
self.__entry.bind('<Control-Key-/>', lambda event: 'break')
self.__entry.bind('<Return>', self.send_message)
self.__entry.focus_set()

def select_all(self, event):
event.widget.selection_range(0, tkinter.END)
return 'break'

def send_message(self, event):
text = self.__entry.get()
self.__entry.delete(0, tkinter.END)
self.__writer.write(text)

def update(self):
self.after(1000, self.update)
self.__monitor.update(self.__messages.update)
for message in self.__messages.get_messages():
self.display(message.name, message.text)

def display(self, name, message):
frame = tkinter.ttk.Frame(self.__text, borderwidth=1, relief='solid')
name = tkinter.ttk.Label(frame, text=name)
text = tkinter.Text(frame, wrap=tkinter.WORD, height=1)
name.grid(row=0, column=0)
text.grid(row=0, column=1, sticky=tkinter.EW)
frame.grid_rowconfigure(0, weight=1)
frame.grid_columnconfigure(1, weight=1)
text.insert('1.0', message)
text.configure(state=tkinter.DISABLED)
self.__text.window_create('1.0', window=frame)

################################################################################

if __name__ == '__main__':
Logos.main('Feeds')

最佳答案

.grid 方法对我来说要正确调整大小/拉伸(stretch)总是有点麻烦。

对于您的代码,我会将 .grid 调用更改为以下 .pack 调用:

frame.pack(expand=1, fill='both')
name.pack(fill='both', side='left')
text.pack(expand=1, fill='both')

然后您也可以放弃 .grid_{row,column}configure 调用。

您的 __text 小部件是否正确调整大小?如果它不调整大小,它也不允许此框架小部件调整大小。

关于python - 在 Python 的 tkinter 中自动调整大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5035824/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com