You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Tkinter生成禁用隐藏文本框时UI元素抖动问题求助

问题分析与解决方案

抖动原因

UI抖动的核心是组件先渲染文本再立刻被清空导致的重复重绘:

  • 在display_words函数中,创建word_widget和diceroll_widget时,会通过insert_text插入文本并禁用组件;
  • 若当前处于隐藏状态,会立刻调用hide_passwords遍历所有组件,把刚插入的文本删掉;
  • 这个"插入→删除"的过程会让组件尺寸瞬间变化,触发两次UI重绘,视觉上就表现为抖动。
    另外hide_passwords里还有逻辑错误:它会重新从组件获取文本覆盖widget_text_dict的内容,当组件被清空后,后续显示时可能拿不到正确的原始文本。

修复方案

方案1:创建组件时直接适配隐藏状态(推荐)

修改display_words的逻辑,创建组件时根据当前password_state决定是否显示文本,避免先插再删的无效操作:

def display_words(pair: dict) -> None:
    text_height = 1
    text_padx = 10

    if self.number_of_dicerolls < 35:
        column_to_be_placed_in = (self.number_of_dicerolls % 5) * 2
        self.number_of_dicerolls += 1
        (diceroll, word), = pair.items()

        # 处理骰子数文本框
        self.diceroll_widget = customtkinter.CTkTextbox(self)
        self.diceroll_widget.grid(row=2 + 2 * ((self.number_of_dicerolls - 1) // 5),
                                  column=column_to_be_placed_in,
                                  pady=(5, 0))
        # 根据状态决定是否插入文本
        if self.password_state == 'shown':
            insert_text(self.diceroll_widget, str(diceroll))
        else:
            self.diceroll_widget.configure(state='disabled')
            self.widget_text_dict[self.diceroll_widget] = str(diceroll)
        self.output_widgets.append(self.diceroll_widget)
        self.text_widgets.append(self.diceroll_widget)

        # 处理单词文本框
        self.word_widget = customtkinter.CTkTextbox(self, font=self.word_font, height=text_height)
        self.word_widget.grid(row=3 + 2 * ((self.number_of_dicerolls - 1) // 5),
                              column=column_to_be_placed_in,
                              pady=(0, 5))
        if self.password_state == 'shown':
            insert_text(self.word_widget, word)
        else:
            self.word_widget.configure(state='disabled')
            self.widget_text_dict[self.word_widget] = word
        self.output_widgets.append(self.word_widget)
        self.text_widgets.append(self.word_widget)

        self.checkbox = customtkinter.CTkCheckBox(master=self,
                                                  text='',
                                                  checkbox_width=20, width=0,
                                                  checkbox_height=20, fg_color='gray',
                                                  hover_color=('grey', 'white'))
        self.checkbox.grid(row=3 + 2 * ((self.number_of_dicerolls - 1) // 5), column=column_to_be_placed_in + 1,
                           sticky='w')
        self.output_widgets.append(self.checkbox)
        # 直接用原始word作为key,避免换行符问题
        self.checkboxes_text[word] = self.checkbox
    else:
        answer = tk.messagebox.askquestion('Dice roll limit reached',
                                           'You have reached the maximum limit of 35 dice rolls. Do you want '
                                           'to clear the screen?', parent=self)
        if answer == 'yes':
            clear_window()

同时修正hide_passwords里的错误逻辑,不要再从组件获取文本:

def hide_passwords() -> None:
    """
    Called when the user clicks the hide button,
    this function hides all passwords.
    """
    for widget, text in self.widget_text_dict.items():
        widget.configure(state='normal')
        widget.delete('0.0', 'end')
        widget.configure(state='disabled')
    self.password_state = 'hidden'
    self.hide_show_button.configure(text='PASSWORDS ARE: HIDDEN', command=show_passwords)

方案2:优化hide_passwords,只处理新增组件

如果不想大改创建逻辑,可以在display_words里记录新增的组件,调用hide_passwords时只处理这些新增组件,避免遍历所有组件:

def display_words(pair: dict) -> None:
    # ... 原有代码 ...
    new_widgets = []
    # 创建diceroll_widget后添加到new_widgets
    new_widgets.append(self.diceroll_widget)
    # 创建word_widget后添加到new_widgets
    new_widgets.append(self.word_widget)
    # ... 其他代码 ...
    if self.password_state == 'hidden':
        # 只清空新增的组件
        for widget in new_widgets:
            widget.configure(state='normal')
            widget.delete('0.0', 'end')
            widget.configure(state='disabled')

额外优化点

  • checkboxes_text里存储的key用原始word而非word_widget.get('1.0', 'end'),避免带上换行符\n,后续复制时无需额外替换;
  • 确认insert_text里的show_copy_menu函数不会触发额外的UI变化。

内容的提问来源于stack exchange,提问作者IceTheDev2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 07:27:01