Change Background Tkinter in Classes - python-3.x

I'm relatively new to Tkinter and Python and just started with Tkinter in object oriented way.
Im trying to change the background colour of all the different pages I have so i have the following code
import tkinter as tk
import sqlite3
from tkinter.ttk import *
from tkinter import *
LARGE_FONT = ("Verdana", 12)
HEIGHT = 700
WIDTH = 800
class programStart(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, minsize=WIDTH)
container.grid_columnconfigure(0, weight=1, minsize=HEIGHT)
self.frames = {}
for F in (StartPage, Register, LoginPage):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise() #Raises to front
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
I have tried container.configure(bg='red') and so on, to no success
How can I go about this issue?

Try this:
import tkinter as tk
import sqlite3
from tkinter.ttk import *
from tkinter import *
LARGE_FONT = ("Verdana", 12)
HEIGHT = 700
WIDTH = 800
class programStart(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, minsize=WIDTH)
container.grid_columnconfigure(0, weight=1, minsize=HEIGHT) #0 minimum, weight is priority
self.frames = {}
for F in (StartPage, Register, LoginPage):
frame = F(container, self, bg="red")
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise() #Raises to front
class StartPage(tk.Frame):
def __init__(self, parent, controller, bg=None, fg=None):
tk.Frame.__init__(self, parent, bg=bg=, fg=fg)
# Make sure that all of the tkinter widgets have `bg=bg=, fg=fg`
Basically you need to tell all of the widgets that you are creating that the background should be red. When creating your widgets you can pass in the bg parameter (background).

This is a minimal version of the system I use to give the user of the GUI the ability to change the colors and fonts of all the widgets in the app according to color schemes he can choose himself.
import tkinter as tk
formats = {
'bg' : 'black',
'fg' : 'white'
}
class Labelx(tk.Label):
def __init__(self, master, *args, **kwargs):
tk.Label.__init__(self, master, *args, **kwargs)
def winfo_subclass(self):
''' a method that works like built-in tkinter method
w.winfo_class() except it gets subclass names
of widget classes custom-made by inheritance '''
subclass = type(self).__name__
return subclass
class Label(Labelx):
'''
If this subclass is detected it will be reconfigured
according to user preferences.
'''
def __init__(self, master, *args, **kwargs):
Labelx.__init__(self, master, *args, **kwargs)
self.config(
bg=formats['bg'],
fg=formats['fg'])
class LabelNegative(Labelx):
'''
If this subclass is detected it will be reconfigured
according to user preferences.
'''
def __init__(self, master, *args, **kwargs):
Labelx.__init__(self, master, *args, **kwargs)
self.config(
bg=formats['fg'],
fg=formats['bg'])
def change_colors():
for widg in (lab1, lab2):
if widg.winfo_class() == 'Label':
if widg.winfo_subclass() == 'Label':
widg.config(bg=formats['fg'], fg=formats['bg'])
elif widg.winfo_subclass() == 'LabelNegative':
widg.config(bg=formats['bg'], fg=formats['fg'])
root = tk.Tk()
f1 = tk.Frame(root)
f1.grid(column=0, row=0)
lab1 = Label(f1, text='Label')
lab1.grid()
lab2 = LabelNegative(f1, text='LabelNegative')
lab2.grid()
button = tk.Button(root, text='colorize', command=change_colors)
button.grid()
root.mainloop()

Related

Tkinter Frozen Screen when start button is clicked

I'm trying to write a tkinter program with start and stop buttons. For both the start and stop buttons, I am importing two different functions from different .py files. When I click on the start button, tkinter freezes and my cursor is constantly "processing" and does not let me click on the stop button.
My tkinter program is below:
import tkinter as tk
from start import hello
from stop import quitprog
class Page(tk.Frame):
def __init__(self, *args, **kwargs):
tk.Frame.__init__(self, *args, **kwargs)
def show(self):
self.lift()
class Page1(Page):
def __init__(self, *args, **kwargs):
Page.__init__(self, *args, **kwargs)
label = tk.Label(self, text="Collecting Data Now...")
label.pack(side="top", fill="both", expand=True)
class Page2(Page):
def __init__(self, *args, **kwargs):
Page.__init__(self, *args, **kwargs)
label = tk.Label(self, text="Analyzing Data Now...")
label.pack(side="top", fill="both", expand=True)
class MainView(tk.Frame):
def __init__(self, *args, **kwargs):
tk.Frame.__init__(self, *args, **kwargs)
p1 = Page1(self)
p2 = Page2(self)
buttonframe = tk.Frame(self)
container = tk.Frame(self)
buttonframe.pack(side="top", fill="x", expand=False)
container.pack(side="top", fill="both", expand=True)
p1.place(in_=container, x=0, y=0, relwidth=1, relheight=1)
p2.place(in_=container, x=0, y=0, relwidth=1, relheight=1)
b1 = tk.Button(buttonframe, text="start", command=hello)
b2 = tk.Button(buttonframe, text="stop", command=quitprog)
b1.pack(side="left")
b2.pack(side="left")
p1.show()
if __name__ == "__main__":
root = tk.Tk()
main = MainView(root)
main.pack(side="top", fill="both", expand=True)
root.wm_geometry("400x400")
root.mainloop()
My start.py is below:
import time
def hello():
for i in range(20):
print("hello world")
time.sleep(1)
My stop.py:
import sys
def quitprog():
sys.exit()
My frozen window:
loading/processing cursor image
Please let me know how to fix this.
Edit: Instead of the start.py program, I'm actually invoking a live twitter stream and that doesn't make use of .sleep(). Instead, there is a continuous flow of twitter data, which causes the program to freeze. Any fixes for this?
You need to use multithreading. Simplest to use (in my opinion) is the standard library multiprocessing module:
import multiprocessing
...
class MainView(tk.Frame):
def __init__(self, *args, **kwargs):
tk.Frame.__init__(self, *args, **kwargs)
p1 = Page1(self)
p2 = Page2(self)
buttonframe = tk.Frame(self)
container = tk.Frame(self)
buttonframe.pack(side="top", fill="x", expand=False)
container.pack(side="top", fill="both", expand=True)
p1.place(in_=container, x=0, y=0, relwidth=1, relheight=1)
p2.place(in_=container, x=0, y=0, relwidth=1, relheight=1)
b1 = tk.Button(buttonframe, text="start", command=self.hello)
b2 = tk.Button(buttonframe, text="stop", command=quitprog)
b1.pack(side="left")
b2.pack(side="left")
p1.show()
def hello(self, *args):
p = multiprocessing.Process(target=hello)
p.start()
quitprog does not need to be run in a separate process,and can't be either, because then sys.exit won't terminate your program.
I only included the MainView class code - make sure to add the rest !

(most likely due to a circular import) how to switch between multiple pages in tkinter?

i've been trying to create a little app for navigate between three pages using tkinter, all the pages are written in different python files, the scripts are bellow.
First file for start page:
import tkinter as tk
from tkinter import ttk
import first_window as fw
import second_window as sw
class Library_Management_System(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
#create a frame who's contain the frames
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 = {} #create a dictionaries for frames
for f in (StartPage, fw.first, sw.second):
frame = f(container, self)
self.frames[f] = frame
frame.grid(row=0, column=0, sticky='nsew')
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
tk.Frame.configure(self, bg='red')
first_button = ttk.Button(self, text='Page One',
command = lambda : controller.show_frame(fw.PageOne)).pack()
second_button = ttk.Button(self, text='Page two',
command = lambda : controller.show_frame(sw.second_window)).pack()
app = Library_Management_System()
app.geometry('200x200+200+200')
app.mainloop()
Second file for first page:
import tkinter as tk
from tkinter import ttk
import main as m
import second_window as sw
class first(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
tk.Frame.configure(self,bg='red')
second_button = ttk.Button(self, text='Page Two',
command=lambda : controller.show_frame(sw.second_window)).pack()
start_button = ttk.Button(self, text='Start Page',
command=lambda : controller.show_frame(m.StartPage)).pack()
Third file for second page:
import tkinter as tk
from tkinter import ttk
import main as m
import first_window as fw
class second(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
tk.Frame.configure(self, bg='green')
start_button = ttk.Button(self, text='Start Page',
command=lambda : controller.show_frame(m.StartPage)).pack()
first_button = ttk.Button(self, text='Page One',
command=lambda : controller.show_frame(fw.first_window)).pack()
i get this error:
for f in (StartPage, fw.first, sw.second):
AttributeError: partially initialized module 'first_window' has no attribute 'first' (most likely due to a circular import)
why it doesn't recognize the module first.

Tkinter window does not update correctly when running

I'm trying to make a Tkinter window show updated data but it only pops up after 13 seconds with just the last value. I want it to pop up and change the values on screen. Mind you, the big goal of this code is to take data from a database (which updates every 3 seconds) and show the data onscreen, while running continuously, so if the answer could include some pointers on the "after" or "update" functions it would be greatly appreciated!
Here is what I have so far.
from tkinter import *
import time
class GUI(Tk):
def __init__(self, *args, **kwargs):
Tk.__init__(self, *args, **kwargs)
Tk.wm_title(self, "Main Window")
self.container = Frame(self)
self.container.pack(side=TOP, fill=BOTH, expand=TRUE)
self.container.grid_rowconfigure(0, weight=1)
self.container.grid_columnconfigure(0, weight=1)
self.frames = {}
self.frame = StartPage(self.container, self)
self.frames[StartPage] = self.frame
self.frame.grid(row=0, column=0, sticky=NSEW)
self.show_frame(StartPage)
def show_frame(self, controller):
frame = self.frames[controller]
frame.tkraise()
class StartPage(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
self.label = Label(self, text="Current ID:\n")
self.label.pack(padx=10, pady=10)
self.data_label = Label(self)
self.data_label.pack()
self.update_data()
def update_data(self):
var1 = StringVar()
for i in range(10):
var1.set(str(i))
self.data_label.config(text=str(i))
time.sleep(1)
main = GUI()
main.mainloop()
I can give you a partial answer. The reason you don't see any updates is that time.sleep() suspends the process and does not allow for tkinter to repaint the window.
You don't use the label textvariable correctly. Specify it in the label and the label will change as you change the textvariable.
You use both pack and grid at the same time which may cause problems.
I have not used after() in a class before so I don't know how to work it, but this example should give you some pointers. I'm keeping console printouts in the code so I can see what it does.
from tkinter import *
import time
class GUI(Tk):
def __init__(self, *args, **kwargs):
Tk.__init__(self, *args, **kwargs)
Tk.wm_title(self, "Main Window")
self.container = Frame(self)
self.container.pack(side=TOP, fill=BOTH, expand=TRUE)
self.frames = {}
self.frame = StartPage(self.container, self)
self.frames[StartPage] = self.frame
self.frame.pack(side=TOP, fill=BOTH, expand=TRUE)
self.show_frame(StartPage)
def show_frame(self, controller):
frame = self.frames[controller]
frame.tkraise()
frame.update_data()
print('Done')
class StartPage(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
self.parent = parent
self.label = Label(self, text="Current ID:\n")
self.label.pack(padx=10, pady=10)
self.var1 = StringVar()
self.data_label = Label(self, textvariable=self.var1)
self.data_label.pack()
self.update_idletasks() # Calls all pending idle tasks
def update_data(self):
if not self.var1.get(): self.var1.set('0')
iteration = int(self.var1.get())
print('iteration', iteration)
if iteration < 3:
iteration = iteration + 1
self.var1.set(str(iteration))
self.update_idletasks() # Calls all pending idle tasks
time.sleep(1)
self.update_data()
main = GUI()
main.mainloop()
You will have to research after() yourself as I can't help you there.

_tkinter.TclError: unknown option "-menu"

I am trying to write the object-oriented code in Python. Now I am stuck with an error:
_tkinter.TclError: unknown option "-menu"
I think the error lies in following line:
self.config(menu=menubar)
Following is my code:
import tkinter as tk
from tkinter import ttk
from PIL import Image, ImageTk
import time
LARGE_FONT = ("Verdana", 12)
class ImgComp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self,width=320, height=209)
container.pack(side="top")
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
container.grid_propagate(False)
self.frames = {}
for F in (PageOne):
frame = F(container, self)
#frame['bg'] = 'red'
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(PageOne)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
menubar = tk.Menu(self)
filemenu = tk.Menu(menubar, tearoff=0)
filemenu.add_command(label="New")
filemenu.add_command(label="Open")
menubar.add_cascade(label="Settings", menu=filemenu)
self.config(menu=menubar)
label = tk.Label(self, text="Page One", font=LARGE_FONT)
label.pack(pady=10,padx=10)
app = ImgComp()
app.mainloop()
Also I would like to inform, I have truncated the code as I was not allowed to post a bigger code by stackoverflow. Please help.

module 'tkinter' has no attribute 'Tk' with python 3.5

Launching my program i visualized this error: "module 'tkinter' has no attribute 'Tk'". So I changed the name of my program from "tkinter.py" to "tkinterrr.py" but I obtain that error as well. What can I do?
That's the code:
import tkinter as tk
LARGE_FONT = ("Verdana", 12)
class SeaofBTCapp(tk.Tk):
def __init__(self, *args, **kwargs): #args all var, kwargs all dict
tk.Tk.__init__(self, *args, **kwargs)
container = Tk.Frame(self) #frame hedge window
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
frame = StartPage(container, self)
self.frames[StartPage] = frame
frame.grid(row=0, column=0, sticky="nsew") #you specify all grid
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont] # key
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Start Page", font=LARGE_FONT) #Label class label object
label.pack(pady=10, padx=10)
app = SeaofBTCapp()
app.mainloop()
Ok I solved... I didn't delete the old "tkinter.py" file from the directory!

Resources