ttk Style won't apply to frame in class - python

just started working with tkinter and i wanted to change the style of the frame but it won't. Can't figure it out so i'm asking you guys.
from tkinter import *
from tkinter import ttk
from tkinter import font
import currencyapi
class Currency():
def __init__(self, parent):
# App settings
parent.title("CoinyAPP")
icon = PhotoImage(file="icon.png")
parent.iconphoto(False, icon)
parent.eval("tk::PlaceWindow . center")
# Font settings
highlightFont = font.Font(
family='Helvetica', name='appHighlightFont', size=12, weight='bold')
# Widgets
self.frame1 = ttk.Frame(
parent, style="Frame1.TFrame").grid(row=0, column=0)
ttk.Label(self.frame1, text="Pick a base currency.", font=highlightFont).grid(
row=0, column=0, padx=48, pady=20)
ttk.Label(self.frame1, text="Pick currency to convert into.", font=highlightFont).grid(
row=0, column=2, padx=18, pady=20)
self.amount = StringVar()
currencyAmount = ttk.Entry(self.frame1, textvariable=self.amount)
currencyAmount.grid(row=1, column=1, padx=40)
self.baseCurrency = StringVar()
base = ttk.Combobox(self.frame1, textvariable=self.baseCurrency, justify='center',
values=list(currencyapi.currencyData['rates'].keys()))
base.grid(row=1, column=0)
base.current(46)
self.convertInto = StringVar()
convert = ttk.Combobox(self.frame1, textvariable=self.convertInto, justify='center',
values=list(currencyapi.currencyData['rates'].keys()))
convert.grid(row=1, column=2)
convert.current(0)
ttk.Button(self.frame1, command=self.currency_convertion,
text='Convert!').grid(row=2, column=1, padx=40, pady=15)
self.result = StringVar()
ttk.Label(self.frame1, font=highlightFont,
textvariable=self.result).grid(row=3, column=1, pady=5)
def currency_convertion(self, *args):
self.conv = currencyapi.currencyData['rates'].get(
self.convertInto.get())
self.amountNumber = self.amount.get()
self.base = currencyapi.currencyData['rates'].get(
self.baseCurrency.get())
Ans = (float(self.conv) * float(self.amountNumber)) / float(self.base)
self.result.set("%.2f" % Ans)
root = Tk()
s = ttk.Style()
s.configure("Frame1.TFrame", background='yellow',
foreground='blue')
Currency(root)
root.mainloop()
It's probably not very well written, sorry for that! Started programming few weeks ago.
Tried to put it into Currency class and outside, both didn't work.

It's possible that the problem is here:
self.frame1 = ttk.Frame(parent, style="Frame1.TFrame").grid(row=0, column=0)
The geometry manager methods (pack, grid, place) return None, so self.frame1 is evaluating to None
To fix this, declare your frame and then put it on the grid separately:
self.frame1 = ttk.Frame(parent, style="Frame1.TFrame")
self.frame1.grid(row=0, column=0)
That said, I put together a quick boilerplate app to test this and it seemed to work without issues...
"""Tkinter Boilerplate App Example"""
import tkinter as tk
from tkinter import ttk
class App(tk.Tk):
def __init__(self):
super.__init__()
self.geometry('200x200')
self.title('Stylish')
self.frame = ttk.Frame(self, style='Frame1.TFrame')
self.frame.pack(expand=True, fill=tk.BOTH) # fill available space
self.style = ttk.Style()
# note: 'foreground' doesn't appear to have any effect on a Frame
self.style.configure('Frame1.TFrame', background='pink', foreground='red')
if __name__ == '__main__':
app = App()
app.mainloop()

Related

Using Tkinter filedialog within a frame and accessing the output globally

I am building my first GUI using tkinter and have come up against some problems. To make the code more modular, I am using an object-oriented approach, as seen in the code below. The basic idea is that I have defined classes for the DataFrame, MetaFrame and SaveFrame, which are all instantiated within the OptionsFrame, which then is instantiated within the MainWindow.
import tkinter as tk
from tkinter import ttk
class DataFrame(ttk.Frame):
def __init__(self, main, *args, **kwargs):
super().__init__(main, *args, **kwargs)
# data frame elements
self.data_label = ttk.Label(self, text="Add Data:")
self.labelled_tweets_label = ttk.Label(self, text="Labelled-Tweets: ")
self.labelled_tweets_button = ttk.Button(self, text="Browse")
self.places_label = ttk.Label(self, text="Places: ")
self.places_button = ttk.Button(self, text="Browse")
self.plots_label = ttk.Label(self, text="Plots Path: ")
self.plots_button = ttk.Button(self, text="Browse")
self.submit_button = ttk.Button(self, text="Submit")
# data frame layout
self.data_label.grid(row=0, column=0, columnspan=2, pady=10)
self.labelled_tweets_label.grid(row=1, column=0)
self.labelled_tweets_button.grid(row=1, column=1)
self.places_label.grid(row=2, column=0)
self.places_button.grid(row=2, column=1)
self.plots_label.grid(row=3, column=0)
self.plots_button.grid(row=3, column=1)
self.submit_button.grid(row=4, column=0, columnspan=2, pady=10)
class MetaFrame(ttk.Frame):
...
class SaveFrame(ttk.Frame):
...
class OptionsFrame(ttk.Frame):
def __init__(self, main, *args, **kwargs):
super().__init__(main, *args, **kwargs)
# options frame components
self.data_frame = DataFrame(self)
self.horiz1 = ttk.Separator(self, orient="horizontal")
self.meta_frame = MetaFrame(self)
self.horiz2 = ttk.Separator(self, orient="horizontal")
self.save_frame = SaveFrame(self)
# options frame layout
self.data_frame.grid(row=0, column=0)
self.horiz1.grid(row=1, column=0, sticky="ew", pady=30)
self.meta_frame.grid(row=2, column=0)
self.horiz2.grid(row=3, column=0, sticky="ew", pady=30)
self.save_frame.grid(row=4, column=0, sticky="s")
class MainWindow(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.geometry("800x600")
self.resizable(False, False)
# configuration
self.columnconfigure(index=0, weight=1)
self.columnconfigure(index=1, weight=2)
# main frames
self.options_frame = OptionsFrame(self, width=400, height=600, borderwidth=1)
self.vert = ttk.Separator(self, orient="vertical")
# main layout
self.options_frame.grid(row=0, column=0)
self.vert.grid(row=0, column=1, sticky="ns")
def main():
root = MainWindow()
root.mainloop()
The layout can be seen in the following image.
This is the basic layout I want within the OptionsFrame. My confusion lies with creating filedialog methods for the three file browsing buttons within the DataFrame. I understand how to use the filedialog class to return the path to a given file, but then this value is restricted to be in the scope of the DataFrame.
I have a back-end that is already developed which requires these file paths, so ideally I would like to access them from the main() function. How is this possible?
Thanks

Tkinter Listbox goes to wrong function

In my code, I have to list boxes that are bound to 2 different functions.
here's the code:
from tkinter import *
import string
class App:
def change_dropdown(self, *args):
print(self.Lb1.curselection())
self.Lb2.insert(self.count, self.choices[self.Lb1.curselection()[0]])
self.count+=1
def delete_dropdown_selected(self, *args):
print(self.Lb2.curselection())
def __init__(self, master):
self.count = 0
self.left = Frame(master)
self.left.config()
self.left.pack(side=LEFT)
self.choices = []
self.yscroll = Scrollbar(master, orient=VERTICAL)
self.Lb1 = Listbox(self.left, selectmode=SINGLE, yscrollcommand=self.yscroll.set, font=50, bd=2)
self.Lb2 = Listbox(self.left, selectmode=SINGLE, bd=2)
for j in range(2):
for i in range(26):
self.Lb1.insert(i,string.ascii_lowercase[i])
self.choices.append(string.ascii_letters[i])
self.Lb1.config(width=50, height=30)
self.Lb1.pack(side=TOP, fill=BOTH, expand=1)
self.Lb2.config(font=30, width=50, height=10)
self.Lb2.pack(side=BOTTOM, fill=BOTH, expand=1, pady=10)
self.Lb2.bind('<<ListboxSelect>>', self.delete_dropdown_selected)
self.Lb1.bind('<<ListboxSelect>>', self.change_dropdown)
self.yscroll.pack(side=LEFT, fill=Y)
self.yscroll.config(command=self.Lb1.yview)
root = Tk()
root.resizable(width=False, height=False)
app = App(root)
root.mainloop()
The problem is that when I click an item in Lb2, it goes to change_dropdown() instead of delete_dropdown_selected(). I don't understand why because I specify it here:
self.Lb2.bind('<<ListboxSelect>>', self.delete_dropdown_selected)
use exportselection=0 option in the Tkinter Listbox.
self.Lb1 = Listbox(self.left, selectmode=SINGLE, yscrollcommand=self.yscroll.set, font=50, bd=2, exportselection=0)
self.Lb2 = Listbox(self.left, selectmode=SINGLE, bd=2, exportselection=0)
How to keep selections highlighted in a tkinter Listbox?

Scrollbar per tab in Notebook not working

I am exploring python right now and i am making a GUI with a Notebook and tabs are made on click at the options menu. My problem is that the scrollbar won't work on every tab. Could anyone help me with this? Here is my code as of now.
from tkinter import *
from tkinter.ttk import *
class Frame:
def __init__(self):
self.root = Tk()
self.root.title("Test")
self.root.resizable(False, False)
self.notebook = Notebook(self.root)
self.notebook.grid(row=1, column=1, padx=2, pady=2)
self.first_tab = Text(height=22, width=50)
self.notebook.add(self.first_tab, text= "tab1")
self.scrollbar = Scrollbar(self.root, command=self.first_tab.yview())
self.first_tab.config(yscrollcommand=self.scrollbar.set)
self.scrollbar.grid(row=1, column=10, sticky="NSW")
self.mb = Menu(self.root)
self.root.config(menu=self.mb)
self.sub_mb = Menu(self.mb, tearoff=0)
self.mb.add_cascade(label='Options', menu=self.sub_mb)
self.sub_mb.add_command(label='Create new tab', command=self.create_new_tab)
def create_new_tab(self):
self.new_tab = Text(height=22, width=50)
self.new_tab.config(yscrollcommand=self.scrollbar.set)
self.notebook.add(self.new_tab, text="New Tab")
def launch(self):
self.root.mainloop()
f = Frame()
f.launch()

tkinter & PIL: removing image

I'm trying to write simple app that would display poster of random movie after button is pressed.
Problem: I don't know how to remove one image before displaying next one (so they don't stack on each other, like here: ).
My shortened code:
from tkinter import *
from tkinter import ttk
import random
from PIL import ImageTk, Image
mlist = ['resized.jpg', 'cat.jpg']
class App(Frame):
def __init__(self, master):
ttk.Frame.__init__(self, master, padding='5')
self.grid(column=0, row=0, sticky=(N, W, E, S))
self.create_button()
self.name = ttk.Label()
self.image = ttk.Label()
def create_button(self):
self.button = ttk.Button(self,
text="Press me",
width=12,
command=lambda: self.display()
).grid(column=0, row=2, columnspan=2, pady=10, sticky=N)
def display(self):
self.name.destroy()
k = random.randrange(0, 2)
self.name = ttk.Label(self, font=(None, 16), text=mlist[k])
self.image = Image.open(mlist[k])
poster = ImageTk.PhotoImage(self.image)
display = ttk.Label(self, image=poster)
display.my_image = poster
display.grid(row=2, column=3, rowspan=3)
self.name.grid(row=0, rowspan=2, column=3)
root = Tk()
root.title("Test")
root.geometry("550x575")
app = App(root)
root.mainloop()
I believe, I should apply something similar to 'self.name.destroy()' on 'self.image'. However doesn't have such method... so how to solve it?

Tkinter custom frame not working

I'm trying to create a custom frame in tkinter, Python v2.7. I have done this just fine once (a frame with a scrollbar), but my second attempt isn't working. I compare it to the Frame that does work, and I can't understand what I have done differently.
What I want is a frame that has a little separator line underneath it, so I'm creating a "normal" frame, a thin frame to use as a separator under it, and a bigFrame to hold it.
Everything I create in the class works, except the frame itself. Hopefully my comments explain what is and isn't showing.
from Tkinter import *
class FunFrame(Frame):
def __init__(self, master, lbl, **kwargs):
self.bigFrame = Frame(master)
Frame.__init__(self, self.bigFrame, width=280, height=200, bg="red", **kwargs)
self.grid(row=0, column=0, pady=3) #this is in bigFrame, and doesn't display
#however the padding is still respected
self.separator = Frame(self.bigFrame, height=2, bd=1, width=280, relief = SUNKEN)
self.separator.grid(row=1, column=0) #this is in bigFrame, and displays
self.l = Label(self, text=lbl) #this is in self and doesn't display
self.l.grid(row=0, column=0)
def grid(self, **kwargs):
self.bigFrame.grid(**kwargs)
if __name__ == "__main__":
root=Tk()
Frame1=FunFrame(root, "hello")
Frame2=FunFrame(root, "world")
Frame1.grid(row=0, column=0)
Frame2.grid(row=1, column=0)
root.mainloop()
If you call self.grid in __init__, it calls your own grid, not Tkinter's version.
Try following (renamed grid to grid_):
from Tkinter import *
class FunFrame(Frame):
def __init__(self, master, lbl, **kwargs):
self.bigFrame = Frame(master)
Frame.__init__(self, self.bigFrame, width=280, height=200, bg="red", **kwargs)
self.grid(row=0, column=0, pady=3)
self.separator = Frame(self.bigFrame, height=2, bd=1, width=280, relief=SUNKEN)
self.separator.grid(row=1, column=0)
self.l = Label(self, text=lbl)
self.l.grid(row=0, column=0)
def grid_(self, **kwargs): ######## grid -> grid_
self.bigFrame.grid(**kwargs)
if __name__ == "__main__":
root=Tk()
Frame1 = FunFrame(root, "hello")
Frame2 = FunFrame(root, "world")
Frame1.grid_(row=0, column=0) ######## grid -> grid_
Frame2.grid_(row=1, column=0) ######## grid -> grid_
root.mainloop()
I'd rather code as follow (if '....' was used to represent hierarchy visually):
from Tkinter import *
class FunFrame(Frame):
def __init__(self, master, lbl, **kwargs):
Frame.__init__(self, master)
if 'inside outer frame (self)':
innerFrame = Frame(self, width=280, height=200, bg="red", **kwargs)
innerFrame.grid(row=0, column=0, pady=3)
if 'inside inner frame':
self.l = Label(innerFrame, text=lbl)
self.l.grid(row=0, column=0)
separator = Frame(self, height=2, bd=1, width=280, relief=SUNKEN)
separator.grid(row=1, column=0)
if __name__ == "__main__":
root = Tk()
Frame1 = FunFrame(root, "hello")
Frame2 = FunFrame(root, "world")
Frame1.grid(row=0, column=0)
Frame2.grid(row=1, column=0)
root.mainloop()

Categories