使用 Tkinter,如何在启动时定位对话框或如何在设置几何后自动调整 window 的大小?
With Tkinter, how to position a dialog box at initiation OR how to auto-resize a window after geometry is set?
免责声明:这很可能是一个 XY 问题,如果您能指出正确的方向,我将不胜感激。
目标: 我有一个文件,我希望 tkinter 读取该文件,然后根据文件内容动态创建小部件。 我希望 window 始终以我的光标为中心打开。
为了 MCVE 让我们考虑一个纯文本文件:
Madness?
This
IS
T K I N T E R
并且 tkinter 应该创建 4 个标签小部件,主要 window 调整大小以适合。这很简单... 直到文件被加密。 在我可以读取加密文件之前,我需要先 askstring()
输入密码(MCVE:让我们假设我们'在这里只要求 key
)。
我的问题:
askstring
对话框始终处于默认位置。我知道它应该是相对于父(根)...
但我无法在创建小部件之前设置 geometry()
否则它不会调整到小部件...
而且我无法预先确定 geometry()
所需的大小,因为没有密码(密钥)我无法打开文件...
这是我最成功尝试的 MCVE 示例:
import tkinter as tk
from tkinter.simpledialog import askstring
from cryptography.fernet import Fernet
class GUI(tk.Tk):
def __init__(self):
super().__init__()
# side note: If I don't withdraw() the root first, the dialog ends up behind the root
# and I couldn't find a way to get around this.
self.withdraw()
self.create_widgets()
# Attempt: I tried doing this instead of self.create_widgets():
# self.reposition()
# self.after(ms=1,func=self.create_widgets)
# The dialog is positioned correctly, but the window size doesn't resize
self.deiconify()
# I have to do the reposition AFTER mainloop or else the window size becomes 1x1
self.after(ms=1, func=self.reposition)
self.mainloop()
def get_key(self):
return askstring('Locked','Enter Key', show='*', parent=self)
def create_widgets(self):
self.lbls = []
with open('test2.txt', 'rb') as file:
encrypted = file.read()
key = self.get_key()
suite = Fernet(key)
self.data = suite.decrypt(encrypted).decode('utf-8')
for i in self.data.split('\n'):
self.lbls.append(tk.Label(self, text=i.strip()))
self.lbls[-1].pack()
def reposition(self):
width, height = self.winfo_width(), self.winfo_height()
self.geometry(f'{width}x{height}+{self.winfo_pointerx()-int(width/2)}+{self.winfo_pointery()-int(height/2)}')
gui = GUI()
实现(我可以接受):
- ✓ 根据文件内容修正大小
- ✓ 根位于光标中心
- ⨯ 提示输入光标中心的键
我的问题是:
是否可以在设置geometry()
后,基于类似于pack_propagate()
的widgets功能再次对root执行自动调整大小?似乎一旦 geometry()
被设置,根将不再传播。
如果没有,我如何在代码中手动调整它的大小?我尝试检索小部件的总高度 height = sum([i.winfo_reqheight() for i in self.lbls])
,但 height
变成了 0
。但是当我在 self.create_widgets()
中 print(self.lbls[-1].winfo_reqheight())
每个 returns 26
时,他们实际上打印 after 我的 self.reposition()
调用, 这很奇怪。
否则,是否可以在创建小部件之前放置 askstring()
对话框?
我被难住了。我觉得我正在以错误的方式解决这个问题,但我不确定处理这种情况以打破依赖循环的正确方法是什么。
为了帮助重现这里的加密字符串和密钥:
数据:
gAAAAABb2z3y-Kva7bdgMEbvnqGGRRJc9ZMrt8oc092_fuxSK1x4qlP72aVy13xR-jQV1vLD7NQdOTT6YBI17pGYpUZiFpIOQGih9jYsd-u1EPUeV2iqPLG7wYcNxYq-u4Z4phkHllvP
密钥:
SecretKeyAnyhowGoWatchDareDevilS3ItsAmazing=
编辑:基于 @BryanOakley's answer here 我可以调用 self.geometry("")
进行重置,但是它会返回到原始 200x200
大小,并且仍然不会传播小部件。
经过多次尝试,我认为我已经成功了,以下是我修改的相关部分:
def __init__(self):
super().__init__()
self.withdraw()
# reposition the window first...
self.reposition()
# For some reason I can't seem to figure out,
# without the .after(ms=1) the dialog still goes to my top left corner
self.after(ms=1, func=self.do_stuff)
self.mainloop()
# wrap these functions to be called by .after()
def do_stuff(self):
self.create_widgets()
self.deiconify()
def reposition(self):
width, height = self.winfo_width(), self.winfo_height()
self.geometry(f'{width}x{height}+{self.winfo_pointerx()-int(width/2)}+{self.winfo_pointery()-int(height/2)}')
# reset the geometry per @BryanOakley's answer in the linked thread
# Seems it resets the width/height but still retains the x/y
self.geometry("")
它会出现 @BryanOakley have answers 对于 tkinter 的所有东西。
我还在等着看是否会有其他人插话这个问题,我很乐意接受你的回答以澄清这个问题。
免责声明:这很可能是一个 XY 问题,如果您能指出正确的方向,我将不胜感激。
目标: 我有一个文件,我希望 tkinter 读取该文件,然后根据文件内容动态创建小部件。 我希望 window 始终以我的光标为中心打开。
为了 MCVE 让我们考虑一个纯文本文件:
Madness?
This
IS
T K I N T E R
并且 tkinter 应该创建 4 个标签小部件,主要 window 调整大小以适合。这很简单... 直到文件被加密。 在我可以读取加密文件之前,我需要先 askstring()
输入密码(MCVE:让我们假设我们'在这里只要求 key
)。
我的问题:
askstring
对话框始终处于默认位置。我知道它应该是相对于父(根)...但我无法在创建小部件之前设置
geometry()
否则它不会调整到小部件...而且我无法预先确定
geometry()
所需的大小,因为没有密码(密钥)我无法打开文件...
这是我最成功尝试的 MCVE 示例:
import tkinter as tk
from tkinter.simpledialog import askstring
from cryptography.fernet import Fernet
class GUI(tk.Tk):
def __init__(self):
super().__init__()
# side note: If I don't withdraw() the root first, the dialog ends up behind the root
# and I couldn't find a way to get around this.
self.withdraw()
self.create_widgets()
# Attempt: I tried doing this instead of self.create_widgets():
# self.reposition()
# self.after(ms=1,func=self.create_widgets)
# The dialog is positioned correctly, but the window size doesn't resize
self.deiconify()
# I have to do the reposition AFTER mainloop or else the window size becomes 1x1
self.after(ms=1, func=self.reposition)
self.mainloop()
def get_key(self):
return askstring('Locked','Enter Key', show='*', parent=self)
def create_widgets(self):
self.lbls = []
with open('test2.txt', 'rb') as file:
encrypted = file.read()
key = self.get_key()
suite = Fernet(key)
self.data = suite.decrypt(encrypted).decode('utf-8')
for i in self.data.split('\n'):
self.lbls.append(tk.Label(self, text=i.strip()))
self.lbls[-1].pack()
def reposition(self):
width, height = self.winfo_width(), self.winfo_height()
self.geometry(f'{width}x{height}+{self.winfo_pointerx()-int(width/2)}+{self.winfo_pointery()-int(height/2)}')
gui = GUI()
实现(我可以接受):
- ✓ 根据文件内容修正大小
- ✓ 根位于光标中心
- ⨯ 提示输入光标中心的键
我的问题是:
是否可以在设置
geometry()
后,基于类似于pack_propagate()
的widgets功能再次对root执行自动调整大小?似乎一旦geometry()
被设置,根将不再传播。如果没有,我如何在代码中手动调整它的大小?我尝试检索小部件的总高度
height = sum([i.winfo_reqheight() for i in self.lbls])
,但height
变成了0
。但是当我在self.create_widgets()
中print(self.lbls[-1].winfo_reqheight())
每个 returns26
时,他们实际上打印 after 我的self.reposition()
调用, 这很奇怪。否则,是否可以在创建小部件之前放置
askstring()
对话框?
我被难住了。我觉得我正在以错误的方式解决这个问题,但我不确定处理这种情况以打破依赖循环的正确方法是什么。
为了帮助重现这里的加密字符串和密钥:
数据:
gAAAAABb2z3y-Kva7bdgMEbvnqGGRRJc9ZMrt8oc092_fuxSK1x4qlP72aVy13xR-jQV1vLD7NQdOTT6YBI17pGYpUZiFpIOQGih9jYsd-u1EPUeV2iqPLG7wYcNxYq-u4Z4phkHllvP
密钥:
SecretKeyAnyhowGoWatchDareDevilS3ItsAmazing=
编辑:基于 @BryanOakley's answer here 我可以调用 self.geometry("")
进行重置,但是它会返回到原始 200x200
大小,并且仍然不会传播小部件。
经过多次尝试,我认为我已经成功了,以下是我修改的相关部分:
def __init__(self):
super().__init__()
self.withdraw()
# reposition the window first...
self.reposition()
# For some reason I can't seem to figure out,
# without the .after(ms=1) the dialog still goes to my top left corner
self.after(ms=1, func=self.do_stuff)
self.mainloop()
# wrap these functions to be called by .after()
def do_stuff(self):
self.create_widgets()
self.deiconify()
def reposition(self):
width, height = self.winfo_width(), self.winfo_height()
self.geometry(f'{width}x{height}+{self.winfo_pointerx()-int(width/2)}+{self.winfo_pointery()-int(height/2)}')
# reset the geometry per @BryanOakley's answer in the linked thread
# Seems it resets the width/height but still retains the x/y
self.geometry("")
它会出现 @BryanOakley have answers 对于 tkinter 的所有东西。
我还在等着看是否会有其他人插话这个问题,我很乐意接受你的回答以澄清这个问题。