Новое окно Tk открывается при изменении цвета фона - PullRequest
0 голосов
/ 16 июня 2019

У меня есть графический интерфейс, который содержит несколько фреймов, каждый из которых содержит несколько меток / полей ввода.Я пытаюсь добавить параметр «Настройки», который позволит пользователю изменять цвет фона всех рамок и меток.До сих пор мне удалось выполнить задачу, однако с предупреждением о появлении нового окна 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.

** Обновление кода, чтобы не отражать глобальные переменные в надежде, что это поможет кому-то еще в будущем.

Я добавил self.controller = controller под каждый класс Frame, объединил pick_color и color_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

Наконец, измените команду Button наcommand=self.controller.pick_color_bg.Благодаря этим изменениям мне удалось устранить необходимость в глобальных переменных.

1 Ответ

1 голос
/ 16 июня 2019

В функции pick_color() вы создаете новый экземпляр Tk(), который получает новый цвет:

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

Чтобы изменить цвет существующего корневого окна, вам нужно сохранить ссылку на него. Также вам придется написать функцию в классе Master(), которая обновляет цвет bg. Цвет не обновляется автоматически при вызове update(), необходимо настроить цвет bg для каждого кадра.

еще немного

У меня проблемы с чтением вашего кода без переписывания. Вы используете имя Master для класса, который создает экземпляр корневого окна. Я бы назвал это Application или похожим, поскольку имя master обычно означает мастер как в «master and server» или, возможно, «parent». Также вы используете имя 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(). Тогда вам не придется использовать глобальные переменные.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...