【问题标题】:Moving Tkinter Window Prevents Resizing on Pack()移动 Tkinter 窗口可防止在 Pack() 上调整大小
【发布时间】:2021-09-28 12:00:25
【问题描述】:

如果我点击一个 Tkinter 窗口并移动它(即使是鼠标点击的结果只有 1px),那么窗口在创建包时不会正确调整大小。它还会将窗口跳回到拖动开始时的位置,而不是创建事件发生时的位置。

例如,这是一个正常运行的示例,我使用after 函数将框架的内容从按住绿色按钮更改为按住灰色按钮:

==[转到]==>

但是,如果我按住鼠标并四处移动窗口,则会发生以下情况:

==[转到]==>

我不知道你能不能看出来,但是窗口没有调整它的大小,导致底部的“停止实验”按钮被切断,“点击我”按钮比它应该的小。

即使用户当时正在拖动窗口,我如何才能确保正确调整窗口大小?我试过root.update(),但没用。

这是我的代码的一个稍微精简的版本:

import tkinter as tk

class MyGui:

    def __init__(self, font=None):  
    
        self.root = tk.Tk()

        self.font = "Arial 12"
        self.font_bold = self.font + " bold"

    def makeLabel(self, text, parent = None):
        
        label = tk.Label(parent, text=text, font=self.font)
        label.pack(fill=tk.X)
    
        return label
        
    def makeButton(self, text, parent, command = None, **style_arguments):
        
        button = tk.Button(parent, text=text, command=command, **style_arguments)
        button.pack(fill=tk.X)
    
        return button

    def makeFrame(self, parent, **style_arguments):
    
        frame = tk.Frame(parent, **style_arguments)
        frame.pack(fill="both")
        
        return frame

    def start(self):
        
        self.root.mainloop()
        
    def stop(self):
        
        self.root.quit()
        self.root.destroy()

def main():

        gui = MyGui()

    gui.makeLabel("Experiment is running", parent = gui.root)
    
    frame_container = gui.makeFrame(parent = gui.root)
    
    gui.makeButton('TIME LEFT: 0', fg = "white", bg = "green", 
                                 font = gui.font_bold, 
                                 parent = frame_container)
                            
    frame_container.after(4000, lambda: switchIt(gui, frame_container))
    
    gui.makeButton('STOP EXPERIMENT', fg = "white", bg = "red", 
                    font = gui.font_bold, parent = gui.root,
                    command = gui.stop)

    gui.start()

def switchIt(gui, frame_container):
    
    # Remove placeholder widgets (if any)
    for child in frame_container.winfo_children():
        child.destroy()
    
    gui.makeButton(
                         "CLICK ME",
                         parent = frame_container, 
                         height=5, width = 40)
    gui.root.update()

main()

main() 是被执行的地方。

(注意:为了最小化可重复性,我取出了对文本时间进行倒计时的代码,因此即使after 函数仍然适用并且会在 appx 4 秒内切换屏幕,它也只会显示 0)。

【问题讨论】:

  • 提供一个完整的工作最小可重现示例。
  • @Art 我以为我有。立即尝试
  • 这可能是因为它无法计算调整窗口大小时所需的大小。您可以尝试在删除按钮(size = gui.root.winfo_geometry())之前存储大小,然后使用gui.root.after(30, gui.root.geometry, size)
  • 但这会有帮助吗?如果我想将窗口的大小恢复到删除/添加小部件之前的大小,您的方法似乎可行。但是,我没有。我希望在删除或添加小部件时动态调整窗口大小,但如果按下鼠标按钮,它根本不会调整大小。
  • (我在上面说郁闷,但我的意思是如果窗口被拖动了一点点)

标签: python user-interface tkinter window


【解决方案1】:

防止窗口在创建或销毁小部件时拒绝调整大小的一种解决方案是暂时禁用标题栏,然后在销毁/创建事件后重新启用它。

例如,将switchIt() 函数更改如下:

def switchIt(gui, frame_container):

    self.gui.root.overrideredirect(True) # <========= ADDED
    
    # Remove placeholder widgets (if any)
    for child in frame_container.winfo_children():
        child.destroy()
    
    gui.makeButton( "CLICK ME", parent = frame_container, height=5, width = 40)
                         
    self.gui.root.overrideredirect(False) # <========= ADDED

如果设置为Trueoverrideredirect() 函数将删除标题栏,如果设置为False,则返回标题栏。 只有在启用标题栏的情况下才能进行拖动。因此,您实际上所做的是在短时间内无法进行拖动。作为奖励,到该点所做的拖动将被保留(窗口不会像以前那样跳回其运动的开始)。

这足够快以至于用户不会注意到它,因为任何窗口调整都会包含在销毁/创建的更大调整中。

一个缺点是鼠标失去了与标题栏的联系,因此当创建/销毁事件发生时(即调用overrideredirect(True) 时)窗口停止拖动。但这并不会让人觉得不自然,因为它似乎是对窗口内容更改的有效响应,并且如果需要重新开始拖动很容易,因为标题栏几乎会立即重新出现。

【讨论】:

    猜你喜欢
    • 2011-06-12
    • 1970-01-01
    • 2014-03-24
    • 2023-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-17
    • 1970-01-01
    相关资源
    最近更新 更多