代码之家  ›  专栏  ›  技术社区  ›  r.ook jpp

使用Tkinter,如何在启动时定位对话框,或如何在设置几何体后自动调整窗口大小?

  •  1
  • r.ook jpp  · 技术社区  · 6 年前

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

    我希望窗口始终以光标为中心打开。

    考虑到MCVE,我们考虑一个纯文本文件,它读取:

    Madness?
    This
    IS
    T K I N T E R
    

    直到文件加密。 askstring() 首先输入密码(MCVE:假设我们只要求 key

    1. 这个 askstring

    2. 但我不能设定 geometry() 在我创建小部件之前,否则它不会调整到小部件的大小。。。

    3. 我不能预先确定 因为我不能打开没有密码(密钥)的文件。。。

    以下是我最成功尝试的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. 是否可以基于类似于的widgets函数再次对根目录执行自动调整大小 pack_propagate() 之后 准备好了吗?好像只有一次 几何() 一旦设置,根将不再传播。

    2. height = sum([i.winfo_reqheight() for i in self.lbls]) 但是 height 只是变得 0 . 但是当我 print(self.lbls[-1].winfo_reqheight()) self.create_widgets() 它回来了 26 每一个,它们都会打印出来 self.reposition() 打电话,这很奇怪。

    3. 否则,是否有可能定位 askstring() 在创建小部件之前的对话框?

    我被难住了。我觉得我走错了路,但我不确定什么是正确的方式来处理这种情况,打破依赖的循环。


    要帮助重新生成加密字符串和密钥,请执行以下操作:

    数据:

    gAAAAABb2z3y-Kva7bdgMEbvnqGGRRJc9ZMrt8oc092_fuxSK1x4qlP72aVy13xR-jQV1vLD7NQdOTT6YBI17pGYpUZiFpIOQGih9jYsd-u1EPUeV2iqPLG7wYcNxYq-u4Z4phkHllvP
    

    密钥:

    SecretKeyAnyhowGoWatchDareDevilS3ItsAmazing=
    

    编辑:基于 @BryanOakley's answer here 我可以调用 self.geometry("") 200x200 大小,但仍然不支持小部件。

    1 回复  |  直到 6 年前
        1
  •  0
  •   r.ook jpp    6 年前

    经过几十次尝试,我想我成功了,以下是我修改的相关部分:

    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

    我还在等着看是否会有其他人插嘴这个问题,并将很高兴接受你的回答,以提供一些明确的主题。