更改背景颜色时,将打开新的Tk窗口

时间:2019-06-16 18:16:20

标签: python-3.x tkinter

我有一个包含多个框架的GUI,每个框架包含多个标签/输入字段。我正在尝试添加一个“设置”选项,该选项将允许用户更改所有框架和标签的背景颜色。到目前为止,我已经设法完成了该任务,但需要警告一个新的Tk窗口,该窗口将弹出并显示选定的背景,而不是在当前窗口上进行更新。

import tkinter as tk
from tkinter import ttk
from tkinter import colorchooser


bg_hex = '#f0f0f0f0f0f0'  #default background color

def pick_color():
    global bg_hex
    bg_color = colorchooser.askcolor()
    bg_hex = bg_color[1]
    Master().update()
    print(bg_hex)


class Master(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        container = tk.Frame(self)
        container.pack(side='top', fill='both', expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)


        self.frames = {}

        for F in (HomePage, PageOne, PageTwo, Settings):        
            frame = F(container, self)
            self.frames[F] = frame
            frame.config(bg = bg_hex)
            frame.grid(row=0, column=0, sticky='nsew')
        self.show_frame(HomePage)

    def show_frame(self, cont):
        frame = self.frames[cont]
        frame.tkraise()



class HomePage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text='Home Page', font=('Verdana', 12), bg=bg_hex)
        label.pack(pady=5)
        button1 = tk.Button(self, text='Page One', command=lambda: controller.show_frame(PageOne))
        button1.pack(pady=5, ipadx=2)
        button2 = tk.Button(self, text='Page Two', command=lambda: controller.show_frame(PageTwo))
        button2.pack(pady=5)
        button3 = tk.Button(self, text='Settings', command=lambda: controller.show_frame(Settings))
        button3.pack(side='bottom', pady=10)

class PageOne(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        tk.Label(self, text='Page One', font='Verdana 14 bold underline', bg=bg_hex).grid(row=0, columnspan=2, pady=5)
        button1 = tk.Button(self, text='Back to Home', command=lambda: controller.show_frame(HomePage))
        button1.grid()


class PageTwo(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        tk.Label(self, text='Page Two', font='Verdana 14 bold underline', bg=bg_hex).grid(row=0, columnspan=2,pady=5)
        button1 = tk.Button(self, text='Back to Home', command=lambda: controller.show_frame(HomePage))
        button1.grid()

class Settings(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        tk.Label(self, text='Settings', font='Verdana 14 bold underline', bg=bg_hex).grid(row=0, columnspan=2,pady=5)
        button1 = tk.Button(self, text='Back to Home', command=lambda: controller.show_frame(HomePage))
        button1.grid() 
        button2 = tk.Button(self, text='Choose Background', command= pick_color)
        button2.grid()

Master().mainloop()

运行代码块时不会发生错误,但是当您选择“选择背景”按钮并选择一种颜色时,将打开一个新的Tk窗口,并显示选定的背景颜色,而不是更新当前的Tk窗口。

**更新代码以不反映全局变量,以希望它可以帮助其他人。

我在每个Frame类下添加了self.controller = controller,将pick_colorcolor_update合并为1个函数,并放置在Tk类下。

def pick_color_bg(self):
    bg_color = colorchooser.askcolor()
    bg_hex = bg_color[1]
    # Loop through pages and contained widgets and set color
    for cls, obj in self.frames.items():
        obj.config(bg=bg_hex)   # Set frame bg color
        for widget in obj.winfo_children():
            if '!label' in str(widget):
                widget.config(bg=bg_hex)    # Set label bg color

最后,将“按钮”命令更改为command=self.controller.pick_color_bg。 通过这些更改,我可以消除对全局变量的需求。

1 个答案:

答案 0 :(得分:1)

在函数pick_color()中,您将创建一个Tk()的新实例,该实例将获得新的颜色:

Master().update()   # Creates a new root window!

要更改现有根窗口的颜色,必须保存对其的引用。另外,您还必须在类Master()中编写一个函数,以更新bg颜色。调用update()时,颜色不会自动更新,必须为每帧配置背景色。

更多

我很难在不重写代码的情况下阅读您的代码。您将名称Master用于实例化根窗口的类。我将其称为Application或与名称master类似的名称通常表示“ master and server”或“ parent”中的master。另外,您使用名称frame(通常是框架的名称)作为不同页面类实例(HomePage等)的名称。这使其难以阅读。就像用红色字母写的蓝色一词一样。

我会用更具描述性的名称来重写它,这样更容易掌握。这样,问题将更易于发现和纠正。

甚至更多

花点时间看一下,但这是一个如何进行较小更改的示例:

import tkinter as tk
from tkinter import ttk
from tkinter import colorchooser


bg_hex = '#f0f0f0f0f0f0'  #default background color

def pick_color():
    global bg_hex
    bg_color = colorchooser.askcolor()
    bg_hex = bg_color[1]
    root.update_color()     # Call function for updating color
    print(bg_hex)


class Master(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        container = tk.Frame(self)
        container.pack(side='top', fill='both', expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)


        self.frames = {}

        for F in (HomePage, PageOne, PageTwo, Settings):        
            frame = F(container, self)
            self.frames[F] = frame
            frame.config(bg = bg_hex)
            frame.grid(row=0, column=0, sticky='nsew')
        self.show_frame(HomePage)

    def show_frame(self, cont):
        frame = self.frames[cont]
        frame.tkraise()

    def update_color(self):
        # Loop through pages and contained widgets and set color
        for cls, obj in self.frames.items():
            obj.config(bg=bg_hex)   # Set frame bg color
            for widget in obj.winfo_children():
                if '!label' in str(widget):
                    widget.config(bg=bg_hex)    # Set label bg color



class HomePage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text='Home Page', font=('Verdana', 12), bg=bg_hex)
        label.pack(pady=5)
        button1 = tk.Button(self, text='Page One', command=lambda: controller.show_frame(PageOne))
        button1.pack(pady=5, ipadx=2)
        button2 = tk.Button(self, text='Page Two', command=lambda: controller.show_frame(PageTwo))
        button2.pack(pady=5)
        button3 = tk.Button(self, text='Settings', command=lambda: controller.show_frame(Settings))
        button3.pack(side='bottom', pady=10)

class PageOne(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        tk.Label(self, text='Page One', font='Verdana 14 bold underline', bg=bg_hex).grid(row=0, columnspan=2, pady=5)
        button1 = tk.Button(self, text='Back to Home', command=lambda: controller.show_frame(HomePage))
        button1.grid()


class PageTwo(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        tk.Label(self, text='Page Two', font='Verdana 14 bold underline', bg=bg_hex).grid(row=0, columnspan=2,pady=5)
        button1 = tk.Button(self, text='Back to Home', command=lambda: controller.show_frame(HomePage))
        button1.grid()

class Settings(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        tk.Label(self, text='Settings', font='Verdana 14 bold underline', bg=bg_hex).grid(row=0, columnspan=2,pady=5)
        button1 = tk.Button(self, text='Back to Home', command=lambda: controller.show_frame(HomePage))
        button1.grid() 
        button2 = tk.Button(self, text='Choose Background', command= pick_color)
        button2.grid()

root = Master()     # Save a reference to the root window
root.mainloop()

我建议不要通过全局范围内的函数来更改颜色。我认为最好将其作为Master()类的函数。然后,您将不必使用全局变量。