繁体   English   中英

使用Tkinter,如何在启动时放置对话框,或者在设置几何形状后如何自动调整窗口大小?

[英]With Tkinter, how to position a dialog box at initiation OR how to auto-resize a window after geometry is set?

免责声明:这很可能是XY问题,如果您能指出正确的方向,我将不胜感激。

目标:我有一个文件,我希望tkinter可以读取该文件,然后根据文件内容动态创建窗口小部件。 我希望窗口始终以光标为中心打开。

为了MCVE的缘故,让我们考虑一个纯文本文件,其内容为:

Madness?
This
IS
T K I N T E R

并且tkinter应该创建4个标签窗口小部件,并调整主窗口的大小以适合该窗口。 这很简单…… 直到文件被加密。 在我可以读取加密文件之前,我需要先要求askstring()输入密码(MCVE:我们还假设我们仅在此处要求输入key )。

我的问题:

  1. askstring对话框始终处于默认位置。 我知道应该是相对于父母(根)...

  2. 但是我无法在创建窗口小部件之前设置geometry() ,否则它将无法调整为窗口小部件的大小...

  3. 而且我无法预先确定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()

可以实现(我可以忍受):

  • ✓根据文件内容正确调整大小
  • ✓根位于光标中心
  • ⨯在光标中心提示输入键

我的问题是:

  1. 设置geometry()后,是否可以基于类似于pack_propagate()的小部件函数在根上再次执行自动调整大小? 似乎一旦设置了geometry() ,根将不再传播。

  2. 如果没有,如何在代码中手动调整其大小? 我尝试检索小部件的总高度height = sum([i.winfo_reqheight() for i in self.lbls])但是height变为0 但是,当我在self.create_widgets() print(self.lbls[-1].winfo_reqheight()) ,它每次返回26 ,而实际上我调用self.reposition() 之后打印,这很奇怪。

  3. 失败了,是否可以在创建小部件之前askstring()对话框?

我很沮丧 我觉得我要走错路了,但是我不确定处理这种情况以打破依赖周期的正确方法是什么。


为了帮助再现,这里是加密的字符串以及密钥:

数据:

gAAAAABb2z3y-Kva7bdgMEbvnqGGRRJc9ZMrt8oc092_fuxSK1x4qlP72aVy13xR-jQV1vLD7NQdOTT6YBI17pGYpUZiFpIOQGih9jYsd-u1EPUeV2iqPLG7wYcNxYq-u4Z4phkHllvP

键:

SecretKeyAnyhowGoWatchDareDevilS3ItsAmazing=

编辑:基于@BryanOakley在这里的答案,我可以调用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对tkinter的所有事情都有答案

我仍然在等待是否会有其他人对此主题提出意见,并且很乐意接受您的回答,以使您对该主题有所了解。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM