【问题标题】:Tkinter buttons not changing back to the correct color after state changing to active状态更改为活动后,Tkinter 按钮未更改回正确的颜色
【发布时间】:2020-10-18 14:07:47
【问题描述】:

我正在制作这个 PDF 工具,我希望在成功导入一个或多个文件之前禁用按钮。这是应用在发布时的样子:

在运行导入文件按钮的回调之后,活动状态如下所示:

我希望按钮的颜色变成栗色而不是原来的灰色。只有将鼠标悬停在它们上方时,它们才会变回栗色。关于如何解决这个问题的任何想法?这是导入按钮的回调:

def import_callback():
    no_files_selected = False
    global files
    files = []
    try:
        ocr_button['state'] = DISABLED
        merge_button['state'] = DISABLED
        status_label.pack_forget()
        frame.pack_forget()
        files = filedialog.askopenfilenames()
        for f in files:
            name, extension = os.path.splitext(f)
            if extension != '.pdf':
                raise
        if not files:
            no_files_selected = True
            raise

        if frame.winfo_children():
            for label in frame.winfo_children():
                label.destroy()
        make_import_file_labels(files)
        frame.pack()

        ocr_button['state'] = ACTIVE
        merge_button['state'] = ACTIVE
    except:
        if no_files_selected:
            status_label.config(text='No files selected.', fg='blue')
        else:
            status_label.config(text='Error: One or more files is not a PDF.', fg='red')
        status_label.pack(expand='yes')


import_button = Button(root, text='Import Files', width=scaled(20), bg='#5D1725', bd=0, fg='white', relief='groove',
                       command=import_callback)
import_button.pack(pady=scaled(50))

【问题讨论】:

  • 你有没有试过在设置配置后调用类似“self.update()”的东西,self是你的框架?
  • @1966bc 在极少数情况下调用update 而不是使用update_idletasks。无论如何,这不会有什么不同,因为没有实现目标的方法。
  • @1966bc 我在根目录和每个按钮上尝试了更新方法,但不确定它的作用或用途。我使用的唯一框架是您在第二张图片中的合并按钮下看到的文件名标签。合并和 ocr 按钮以及其他所有内容都打包到根目录中。

标签: python-3.x tkinter


【解决方案1】:

我知道这是很久以前提出的问题,所以可能已经为用户解决了。但是由于我遇到了完全相同的问题并且在这里没有看到“最简单”的答案,所以我想我会发布:

只需将状态从“活动”更改为“正常”

ocr_button['state'] = NORMAL
merge_button['state'] = NORMAL

我希望这对未来的用户有所帮助!

【讨论】:

    【解决方案2】:

    据我了解,你想要类似的东西:

    ...
    ocr_button['state'] = DISABLED
    ocr_button['background'] = '#*disabled background*'
    ocr_button.bind('<Enter>', lambda e:ocr_button.configure(background='#...'))
    ocr_button.bind('<Leave>', lambda e:ocr_button.configure(background='#...'))
    
    merge_button['state'] = DISABLED
    merge_button['background'] = '#*disabled background*'
    merge_button.bind('<Enter>', lambda e:ocr_button.configure(background='#...'))
    merge_button.bind('<Leave>', lambda e:ocr_button.configure(background='#...'))
    ...
    
    ...
    ocr_button['state'] = ACTIVE
    ocr_button['background'] = '#*active background*'
    ocr_button.unbind('<Enter>')
    ocr_button.unbind('<Leave>')
    
    merge_button['state'] = ACTIVE
    merge_button['background'] = '#*active background*'
    merge_button.unbind('<Enter>')
    merge_button.unbind('<Leave>')
    ...
    

    如果有任何错误,因为我把它写出来或者有什么不清楚的地方,请告诉我。

    更新

    以下代码重现了您所说的行为。发生这种情况的原因是 tkinter 如何设计标准行为。如果您考虑style of ttk 小部件,您将对它有更好的理解。所以我建议不要使用state 的自动设计,而是写几行代码来配置你喜欢的按钮,添加和删除命令,改变你喜欢的背景。如果你不想写这几行,你将不得不使用ttk.Button映射你喜欢的行为

    import tkinter as tk
    
    root = tk.Tk()
    def func_b1():
        print('func of b1 is running')
    def disable_b1():
        b1.configure(bg='grey', command='')
    def activate_b1():
        b1.configure(bg='red', command=func_b1)
    
    
    b1 = tk.Button(root,text='B1', bg='red',command=func_b1)
    b2 = tk.Button(root,text='disable', command=disable_b1)
    b3 = tk.Button(root,text='activate',command=activate_b1)
    
    b1.pack()
    b2.pack()
    b3.pack()
    
    root.mainloop()
    

    【讨论】:

    • 导入按钮回调完成后,我希望合并按钮和 ocr 按钮看起来与第一张图片中的导入按钮完全相同。但是现在,在导入按钮回调之后,合并和 ocr 按钮只有在您将鼠标悬停在它们上方时才会恢复为导入按钮的外观。这很奇怪,因为我没有创建和绑定,也不想这样做,除非绑定是某种解决方案。
    • @GabeMorris 这或多或少是按钮的正常行为。我添加了一个例子和它的解释。
    • 这是相同的行为。似乎当一个按钮被激活时,它会将背景恢复为原始灰色。我需要让它到用户不能调用合并和 ocr 按钮回调的地方,直到“文件”变量不是无。我想如果 files 为 None,我只需要在我的 ocr/merge 回调中引发异常。但是删除命令是什么意思?
    • @GabeMorris 所以我创建了禁用b1 并再次激活它的功能。因此,您可以将这些函数添加到您的代码中,或者添加使用选项 state 这会扰乱您的设计。
    • 啊啊啊我明白了。我试过你的逻辑,它奏效了。只需使用空命令关闭按钮并在导入文件回调中配置命令并更改颜色。谢谢!
    【解决方案3】:

    我编写了这个简单的应用程序,我认为它可以帮助所有人重现问题。

    请注意,单击时按钮的状态为 Active。

    #!/usr/bin/python3
    import sys
    import tkinter as tk
    from tkinter import ttk
    from tkinter import messagebox
    
    class Main(ttk.Frame):
    
        def __init__(self, parent, *args, **kwargs):
            super().__init__()
    
    
            self.parent = parent
            self.init_ui()
    
        def cols_configure(self, w):
    
            w.columnconfigure(0, weight=0,  minsize=100)
            w.columnconfigure(1, weight=0)
            
            w.rowconfigure(0, weight=0, minsize=50)
            w.rowconfigure(1, weight=0,)
            
            
    
        def get_init_ui(self, container):
            
            w = ttk.Frame(container, padding=5)
            self.cols_configure(w)
            w.grid(row=0, column=0, sticky=tk.N+tk.W+tk.S+tk.E)
    
            return w        
              
        def init_ui(self):
    
            w = self.get_init_ui(self.parent)
    
            r = 0
            c = 0
            
            b = ttk.LabelFrame(self.parent, text="", relief=tk.GROOVE, padding=5)
       
            self.btn_import = tk.Button(b,
                                        text="Import Files",
                                        underline=1,
                                        command = self.on_import,
                                        bg='#5D1725',
                                        bd=0,
                                        fg='white')
            self.btn_import.grid(row=r, column=c, sticky=tk.N+tk.W+tk.E,padx=5, pady=5)
              
            self.parent.bind("<Alt-i>", self.switch)
    
            r +=1
    
            self.btn_ocr = tk.Button(b,
                                        text="OCR FIles",
                                        underline=0,
                                        command = self.on_ocr,
                                        bg='#5D1725',
                                        bd=0,
                                        fg='white')
    
            self.btn_ocr["state"] = tk.DISABLED
            
            self.btn_ocr.grid(row=r, column=c, sticky=tk.N+tk.W+tk.E,padx=5, pady=5)
    
            r +=1
    
            self.btn_merge = tk.Button(b,
                                        text="Merge Files",
                                        underline=0,
                                        command = self.on_merge,
                                        bg='#5D1725',
                                        bd=0,
                                        fg='white')
    
            self.btn_merge["state"] = tk.DISABLED
            
            self.btn_merge.grid(row=r, column=c, sticky=tk.N+tk.W+tk.E,padx=5, pady=5)
              
            r +=1
    
            self.btn_reset = tk.Button(b,
                                        text="Reset",
                                        underline=0,
                                        command = self.switch,
                                        bg='#5D1725',
                                        bd=0,
                                        fg='white')
            self.btn_reset.grid(row=r, column=c, sticky=tk.N+tk.W+tk.E,padx=5, pady=5)
              
            
            b.grid(row=0, column=1, sticky=tk.N+tk.W+tk.S+tk.E)
    
    
        def on_import(self, evt=None):
            
            self.switch()
            #simulate some import
            self.after(5000, self.switch())
            
            
        def switch(self,):
    
            state = self.btn_import["state"]
            
            if state == tk.ACTIVE:
                self.btn_import["state"] = tk.DISABLED
                self.btn_ocr["state"] = tk.NORMAL
                self.btn_merge["state"] = tk.NORMAL
                
            else:
                self.btn_import["state"] = tk.NORMAL
                self.btn_ocr["state"] = tk.DISABLED
                self.btn_merge["state"] = tk.DISABLED
                
               
        def on_ocr(self, evt=None):
            state = self.btn_ocr["state"]
            print ("ocr button state is {0}".format(state))
            
            
    
        def on_merge(self, evt=None):
            state = self.btn_merge["state"]
            print ("merge button state is {0}".format(state))
            
            
        def on_close(self, evt=None):
            self.parent.on_exit()
    
    class App(tk.Tk):
        """Main Application start here"""
        def __init__(self, *args, **kwargs):
            super().__init__()
    
            self.protocol("WM_DELETE_WINDOW", self.on_exit)
            self.set_style()
            self.set_title(kwargs['title'])
                
            
            Main(self, *args, **kwargs)
           
        def set_style(self):
            self.style = ttk.Style()
            #('winnative', 'clam', 'alt', 'default', 'classic', 'vista', 'xpnative')
            self.style.theme_use("clam")
            
    
        def set_title(self, title):
            s = "{0}".format('Simple App')
            self.title(s)
            
        def on_exit(self):
            """Close all"""
            if messagebox.askokcancel(self.title(), "Do you want to quit?", parent=self):
                self.destroy()
    
    def main():
    
        args = []
    
        for i in sys.argv:
            args.append(i)
    
        kwargs = {"style":"clam", "title":"Simple App",}
    
        app = App(*args, **kwargs)
    
        app.mainloop()
    
    
    if __name__ == '__main__':
        main()            
        
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-09-24
      • 1970-01-01
      • 1970-01-01
      • 2014-02-22
      • 1970-01-01
      • 1970-01-01
      • 2016-11-07
      相关资源
      最近更新 更多