【问题标题】:Is it possible to center a tkinter.simpledialog window?是否可以将 tkinter.simpledialog 窗口居中?
【发布时间】:2021-12-22 11:56:56
【问题描述】:

我在一个更大的脚本中包含了条件密码捕获。代码如下所示:

if thing:  # found token, don't need password
    do stuff
else:  # no token, get password in popup
    try:
        import tkinter as tk
        import tkinter.simpledialog
        tk.Tk().withdraw()
        passwd = tkinter.simpledialog.askstring("Password", "Enter password:", show="*")
        return passwd

功能上没问题,但我的大多数用户都使用 3840x1600 分辨率的显示器,所以当对话框在左上方弹出时很容易错过。

是否有一种简单的方法来覆盖 simpledialog 类以告诉它出现在监视器上的某个 X/Y 位置,或者我唯一的选择是构建完整的mainloop()

【问题讨论】:

    标签: python tkinter tk


    【解决方案1】:

    由于对话框相对于其父级的位置放置,因此您可以将其父级居中,即在您的情况下为根窗口:

    import tkinter as tk
    from tkinter import simpledialog
    
    root = tk.Tk()
    # center root window
    root.tk.eval(f'tk::PlaceWindow {root._w} center')
    root.withdraw()
    
    # set parent=root
    passwd = simpledialog.askstring('Password', 'Enter password:', show='*', parent=root)
    

    【讨论】:

      【解决方案2】:

      所以当对话框在左上角弹出时很容易错过。

      如果您指定可选参数parent,对话框将出现在窗口中间并在内部获得焦点。确保您的窗口通过.update_idletasks() 映射以获取相应的坐标。你也可以考虑让你的窗口透明而不是撤回。

      import tkinter as tk
      import tkinter.simpledialog
      
      def ask_pw():
          pw = tkinter.simpledialog.askstring("Password",
                                              "Enter password:",
                                              show="*",
                                              parent=root)
      root = tk.Tk()
      root.geometry('250x250+500+500')
      root.update_idletasks()
      ask_pw()
      #root.withdraw()
      root.mainloop()
      

      【讨论】:

      • 低摩擦,简短,正是我正在寻找的,用于获取密码的后备。谢谢
      【解决方案3】:

      我找不到覆盖任何类以直接修改底层_QueryString 类的方法(它也是私有的,所以我不想使用它,我可能找不到简单的方法无论如何)。所以我只写了一个自定义的askstring 函数。该功能是这样的,您需要提供父级和几何图形,它将首先安排一个内部函数(可能是一个适当的外部函数,但应该没问题)以获取该父级的小部件中的最后一个小部件并在计划之后时间应该是新的对话框,所以它应该得到它。 (检查该小部件是否派生自dialog.Dialog,这是从_QueryString 继承的)。然后只需更改几何图形(因为在继承链上方有Toplevel,它显然有一个geometry 方法):

      import tkinter as tk
      import tkinter.simpledialog as dialog
      
      
      def askstring(title, prompt, geometry='', **kwargs):
          def change_geometry():
              if not geometry:
                  return
              widget = kwargs['parent'].winfo_children()[-1]
              if isinstance(widget, dialog.Dialog):
                  widget.geometry(geometry)
      
          if 'parent' in kwargs:
              kwargs['parent'].after(10, change_geometry)
          return dialog.askstring(title, prompt, **kwargs)
      
      
      root = tk.Tk()
      root.withdraw()
      
      askstring('Title', 'Prompt', geometry='300x200+200+200', parent=root)
      

      有用:

      【讨论】:

      • 您可能对this link感兴趣。遗憾的是,这些天没有 effbot。
      • @Atlas435 感谢您的链接,我错过了它基于父级设置其几何形状(这次甚至没有阅读它的代码,直接继承并立即失败,因为它是无法从稍后被同一对象覆盖的对象继承)并尝试找到其他解决方案,但是如果必须设置几何图形而不是基于父级的位置或更大的尺寸,则必须使用它,或者只是使用Dialog创建一个自定义的
      • 是的,我喜欢你的工作,它的创意很好。这就是为什么我也赞成这个答案。一个服装 Dialog 甚至有点棘手,如果你尝试模仿返回效果,你会注意到。
      • @Atlas435 我认为在这一点上复制粘贴 _QueryString 类添加几何参数然后复制 askstring 函数会更简单(只需复制粘贴到您的源代码),你就设置好了。 (也可以继承,但正如我的回答中提到的,它是一个私有类)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-05-10
      • 2018-03-22
      • 1970-01-01
      • 2011-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多