tkinter - Scrollbar in Canvas not working - python

I've searched stack overflow but most of the solutions don't seem to work for me or the answers aren't clear enough and I don't know where/how I should be using the code.
My horizontal scroll bar in the AddSubject Frame isn't working for some reason. how do I get the horizontal scrollbar working?
AddSubjects Frame
Here is my code:
import tkinter as tk
from tkinter import ttk
import tkinter.scrolledtext as tks
class Program(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.iconbitmap(self, default = "")
tk.Tk.wm_title(self, "")
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 (SubjectHome, AddSubject):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row = 0, column = 0, sticky = "nsew")
self.show_frame(SubjectHome)
def show_frame(self,cont):
frame = self.frames[cont]
frame.tkraise()
class SubjectHome(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
ttk.Style().configure("TButton", padding=6, relief="flat", background="#ccc")
name = tk.Label(self, text = "User: FirstName + LastName")
name.pack(anchor="ne")
pagename = tk.Label(self, text = "Subject Menu")
pagename.pack(anchor="n")
self.innerFrame = tk.Frame(self, bg="red")
self.innerFrame.place(relx=.5, rely=.5, anchor="c")
view = ttk.Button(self.innerFrame, text = "View Subjects", command = lambda: controller.show_frame(ViewSubject))
view.grid(row=0, sticky="W"+"E")
add = ttk.Button(self.innerFrame, text = "Add Subjects", command = lambda: controller.show_frame(AddSubject))
add.grid(row=1, sticky="W"+"E")
class AddSubject(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
name = tk.Label(self, text = "User: FirstName + LastName")
name.pack(anchor="ne")
pagename = tk.Label(self, text = "Add Subjects")
pagename.pack(anchor="n")
self.innerFrame = tk.Frame(self)
self.innerFrame.place(relx=.5, rely=.5, anchor="c")
canvas = tk.Canvas(self.innerFrame)
self.firstFrame = tk.Frame(canvas)
self.firstFrame.pack(anchor="n")
info = tk.Label(self.innerFrame, text = "Information...\n Information....")
info.pack()
for x in range(5):
pagename = tk.Label(self.firstFrame, text = "Unit Name")
pagename.grid(row=0, column=x)
self.text = tks.ScrolledText(self.firstFrame, width=50)
self.text.grid(row=1, column=x ,sticky="E")
scrollbar = tk.Scrollbar(self.innerFrame, orient="horizontal", command=canvas.xview)
canvas.configure(xscrollcommand=scrollbar.set)
scrollbar.pack(side="bottom", fill="x")
canvas.pack(side="left", fill="both", expand=True)
back = ttk.Button(self.innerFrame, text = "Back", command = lambda: controller.show_frame(SubjectHome))
back.pack(anchor="sw")
next = ttk.Button(self.innerFrame, text = "Next")
next.pack(anchor="se")
app = Program()
app.state('zoomed')
app.mainloop()

For a widget to be scrollable on a canvas, it has to be added to the canvas with create_window. If you call pack or grid or place to put widgets in a canvas, they will not scroll.

Related

How to change the borderwidth and relief of 1 ttk combobox

I am wanting to change the borderwidth and relief of a ttk combobox. But I only want to change these attributes for 1 combobox. Is there a way to make the second combobox have a borderwidth of 3 and a relief of solid, like the text box 2?
import tkinter as tk
from tkinter import font as tkfont, filedialog, messagebox
from tkinter.ttk import Combobox
class SLS_v1(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# Setting up the root window
self.title('APP')
self.geometry("552x700")
self.resizable(False, False)
self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")
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 = {}
self.frames["MenuPage"] = MenuPage(parent=container, controller=self)
self.frames["MenuPage"].grid(row=0, column=0, sticky="nsew")
self.show_frame("MenuPage")
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
class MenuPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
text1 = tk.Text(self, width=25, height=1)
text1.pack(pady=20)
combobox1 = tk.ttk.Combobox(self, width=25, height=2, state='readonly')
combobox1.pack(pady=20)
text2 = tk.Text(self, width=50, borderwidth=3, relief='solid', height=1)
text2.pack(pady=20)
combobox2 = tk.ttk.Combobox(self, width=50, height=5, state='readonly')
combobox2.pack(pady=20)
if __name__ == "__main__":
app = SLS_v1()
app.mainloop()
To change ttk objects you must define the style like this.
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.style = ttk.Style(self)
self.style.theme_use("default")
Then you can define specifics for your Combobox like this.
self.style.configure("K.TCombobox",
**dict(
padding = 1, arrowsize = 12,
borderwidth = 3, relief = "solid"))
Complete implementation like this.
combobox2 = Combobox(self, width=50, height=5, state='readonly', style = "K.TCombobox")

Buttons and Labels Will Not Show Up in Window

The buttons and labels will not show up in my window. If I delete self from the parenthesis (or insert controller instead), the buttons will show up. However, the buttons do not raise the underlying window to the front as it is supposed to. I used a similar code that used pack, and it worked well. I can't seem to find the problem of why using grid won't work. I'm a bit of a beginner to tkinter so perhaps I'm missing something obvious.
import tkinter as tk
LARGE_FONT= ("Verdana", 12)
NORM_FONT= ("Verdana", 10)
SMALL_FONT= ("Verdana", 8)
class mGui(tk.Tk):
def __init__(self, *args, **kargs):
tk.Tk.__init__(self, *args, **kargs)
container = tk.Frame(self)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (StartPage, PageOne):
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)
label_1 = tk.Label(self, text = "Start Page", font = LARGE_FONT)
label_1.grid(row = 0, column = 0)
button1 = tk.Button(self,text = "Go", command = lambda: controller.show_frame(PageOne))
button1.grid(row = 1, column = 0)
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label_1 = tk.Label(self, text = "Page One", font = LARGE_FONT)
label_1.grid(row = 1, column = 4)
button1 = tk.Button(self, text = "Go Back", command = lambda: controller.show_frame(StartPage))
button1.grid(row = 4, column = 1)
app = mGui()
app.mainloop()
You need to add a call to the grid() layout manager for the container Frame as shown:
.
.
.
class mGui(tk.Tk):
def __init__(self, *args, **kargs):
tk.Tk.__init__(self, *args, **kargs)
container = tk.Frame(self)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
container.grid() # ADD THIS.
.
.
.

having issues with the if statement

With the if-statement that I have put in, it would only display the lose statement even if it is correct.
I'm not sure if the way I wrote the statement is correct.
I'm trying to make it that when pressing start both labels would show a number between 1 to 21.
Also, if it's possible, I want to make it that when the hit button is pressed, a number would be added to the label. For example, pressing hit would add 10 + 5, then display the total.
LOCATED IN CLASS TTY:
import tkinter as tk
k = 10
Q = 10
J = 10
A = 11 or 1
class WINDOW(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "Memory") #sets the window title
container = tk.Frame(self)#Name of frame to refer to
container.pack(side="top", fill="both", expand=True)#size of window
container.grid_rowconfigure(0, weight=4)#size of window
container.grid_columnconfigure(0, weight=4)
self.frames = {}
for F in (MainMenu, tty):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("MainMenu")
def show_frame(self, page_name):
frame = self.frames[page_name]
frame.tkraise()
class MainMenu(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.configure(background = 'white')
label = tk.Label(self, text="Memory",font=(15),
borderwidth=5, relief="solid")
label.pack(side="top", fill="y", pady=15, padx=270)
label.pack(fill="both")
button1 = tk.Button(self, text="Start", relief="solid",
borderwidth=5,width=30,
font=(17),command=lambda:
controller.show_frame("tty"))
button1.pack()
button3 = tk.Button(self,
text="Quit",relief="solid",borderwidth=4,width=30,font=(17),command = quit)
button3.place(x="420", y ="50")
button3.pack()
class tty(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.configure(background = "white")
def win():
if score > deal:
tts = tk.Label(self, text="win", font=(20))
tts.pack()
else:
lose = tk.Label(self, text="lose", font=(10))
lose.pack() #The if statement
deal = tk.Label(self, text="18", font=(18))
deal.pack(side="top", fill="y", pady=15, padx=270)
score = tk.Label(self, text="19", font=(18))
score.pack()
f = tk.Frame(self)
button1 = tk.Button(f,borderwidth=5, text="stand", font=(18),command =
lambda: win())#This is the button that i want to display the label
button1.grid(row=0,column=0)
button2 = tk.Button(f, text="Hit",borderwidth=5, font=(18))
button2.grid(row=0,column=1)
f.pack(side="bottom")
button3 = tk.Button(self, text="Quit", font=(18))
button3.pack(side="right", pady=50)
if __name__ == "__main__":
app = WINDOW()
app.geometry("800x400")
app.mainloop()
if score > deal: is comparing two tkinter label objects rather than the value of score and deal. Try getting the value of the labels and converting them to integers before doing the comparision.
if int(score['text']) > int(deal['text']):
To help with your other questions.
To chose a random number between 1 and 21, use the randint function contained inside python's random module (see code below). I've added a new randomise function which will be called after the page is created to randomly select a value for deal and score.
With the hit button, i've added a new function hit which will take the current score, and add another random value to it.
import tkinter as tk
from random import randint
k = 10
Q = 10
J = 10
A = 11 or 1
class WINDOW(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "Memory") #sets the window title
container = tk.Frame(self)#Name of frame to refer to
container.pack(side="top", fill="both", expand=True)#size of window
container.grid_rowconfigure(0, weight=4)#size of window
container.grid_columnconfigure(0, weight=4)
self.frames = {}
for F in (MainMenu, tty):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("MainMenu")
def show_frame(self, page_name):
frame = self.frames[page_name]
frame.tkraise()
class MainMenu(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.configure(background = 'white')
label = tk.Label(self, text="Memory",font=(15),
borderwidth=5, relief="solid")
label.pack(side="top", fill="y", pady=15, padx=270)
label.pack(fill="both")
button1 = tk.Button(self, text="Start", relief="solid",
borderwidth=5,width=30,
font=(17),command=lambda:
controller.show_frame("tty"))
button1.pack()
button3 = tk.Button(self,
text="Quit",relief="solid",borderwidth=4,width=30,font=(17),command = quit)
button3.place(x="420", y ="50")
button3.pack()
class tty(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.configure(background = "white")
self.deal = tk.Label(self, text="18", font=(18))
self.deal.pack(side="top", fill="y", pady=15, padx=270)
self.score = tk.Label(self, text="19", font=(18))
self.score.pack()
f = tk.Frame(self)
button1 = tk.Button(f,borderwidth=5, text="stand", font=(18),command = self.win)#This is the button that i want to display the label
button1.grid(row=0,column=0)
button2 = tk.Button(f, text="Hit",borderwidth=5, font=(18),command = self.hit)
button2.grid(row=0,column=1)
f.pack(side="bottom")
button3 = tk.Button(self, text="Quit", font=(18))
button3.pack(side="right", pady=50)
self.randomise()
def randomise(self):
self.deal['text'] = str(randint(1,21))
self.score['text'] = str(randint(1,21))
def hit(self):
current_score = int(self.score['text'])
new_score = current_score + randint(1,21)
self.score['text'] = str(new_score)
def win(self):
if int(self.score['text']) > int(self.deal['text']):
tts = tk.Label(self, text="win", font=(20))
tts.pack()
else:
lose = tk.Label(self, text="lose", font=(10))
lose.pack() #The if statement
if __name__ == "__main__":
app = WINDOW()
app.geometry("800x400")
app.mainloop()

the tkinter widgets in my classes are not displaying

I'm trying to write a code that contains multiple pages and can be switched to when a button is clicked on. it worked initially but my widgets are not displaying, and there is neither a warning or an error message. Secondly, what is the difference between using tk and tk.TK?
from tkinter import *
import tkinter as tk
class moreTab(tk.Tk):
def __init__(self):
Tk.__init__(self)
self.geometry("1200x600")
container = Frame(self, bg='#c9e3c1')
container.pack(side = "top", fill = 'both', expand = True)
container.grid_rowconfigure(0, weight = 1)
container.grid_columnconfigure(0, weight = 1)
self.frames = {}
for q in (pageone, widget):
frame = q(container,self)
self.frames[q] = frame
frame.place(x= 0,y = 0)
self.raise_frame(pageone)
def raise_frame(self,cont):
frame = self.frames[cont]
frame.tkraise()
class widget(Frame):
def __init__(self, master, control):
Frame.__init__(self, master)
lab = tk.Label(self, text="main page")
lab.place(x = 10, y = 40)
but = tk.Button(self, text='visit start page', command=lambda:
control.raise_frame(pageone))
but.place(x = 10, y = 70)
class pageone(Frame):
def __init__(self, master, control):
Frame.__init__(self,master)
lab = Label(self, text = 'welcome to Game Analysis')
lab.place(x = 10, y = 10)
but = Button(self, text = "Start", command = lambda:
control.raise_frame(widget))
but.place(x = 10, y = 20)
app = moreTab()
app.mainloop()
It turns the issue was that you were using place(). Use the grid geometry manager. Using both import tkinter as tk and from tkinter import * is meaningless. Use one and be consistent. If you use the latter, you have everything available, hence you will write, say Button(...). But if you use the former, you will have to refer each widget like tk.Button(...).
import tkinter as tk
class moreTab(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.geometry("1200x600")
container = tk.Frame(self, bg='#c9e3c1')
container.pack(side = "top", fill = 'both', expand = True)
container.grid_rowconfigure(0, weight = 1)
container.grid_columnconfigure(0, weight = 1)
self.frames = {}
for q in (pageone, widget):
frame = q(container, self)
self.frames[q] = frame
frame.grid(row=0, column=0, sticky='nsew')
self.raise_frame(pageone)
def raise_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class widget(tk.Frame):
def __init__(self, master, control):
tk.Frame.__init__(self, master)
lab = tk.Label(self, text="main page")
lab.grid(row=0, column=0, padx=10, pady=10)
but = tk.Button(self, text='visit start page', command=lambda: control.raise_frame(pageone))
but.grid(row=1, column=0, padx=10, pady=10)
class pageone(tk.Frame):
def __init__(self, master, control):
tk.Frame.__init__(self, master)
lab = tk.Label(self, text = 'welcome to Game Analysis')
lab.grid(row=0, column=0, padx=10, pady=10)
but = tk.Button(self, text = "Start", command = lambda: control.raise_frame(widget))
but.grid(row=1, column=0, padx=10, pady=10)
app = moreTab()
app.mainloop()

Why are my widgets not showing up on the 3rd screen

When you select 2 duelist on the second screen the program shows a 3rd screen that should display 2 labels and 2 entry widgets for the user to enter the names of the players. But I can't seem to figure out why the widgets are not showing up. The section of code that involves this issue is the the block for the class TwoPlayer. Thank you!
import tkinter as tk
largeFont = ("Veranda", 18)
field1 = 'Duelist 1', 'Duelist 2'
names = []
class Yugioh_backEnd(tk.Tk):
#set default initializion
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "YuGiOh Duel Calculator")
#containers
container = tk.Frame(self)
#set pack method for container
container.pack(side="top", fill="both", expand=True)
#set grid method for container
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
#selects which frame to show
self.frames = {}
for F in (StartPage, NumPlayers, TwoPlayer):
frame = F(container, self)
self.frames[F]=frame
frame.grid(row=0, column=0, sticky="nsew")
#show Frame
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)
#greet the user
greeting = tk.Label(self, text = "Welcome to\n YuGiOh Duel Calculator!", font = largeFont)
greeting.pack(pady=(10,40),padx=30)
#Enter the next window
lets_duel = tk.Button(self, text="Lets Duel!!!", command=lambda: controller.show_frame(NumPlayers))
lets_duel.pack(pady=(0,30),padx=30)
class NumPlayers(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
#prompt for players quantity
prompt1 = tk.Label(self, text = "How many duelist?", font = largeFont)
prompt1.pack(pady=(10,40),padx=30)
#Number of players
twoPlayers = tk.Button(self, text = "2 Duelists", command=lambda: controller.show_frame(TwoPlayer))
return1 = tk.Button(self, text="Return Home", command=lambda: controller.show_frame(StartPage))
#Add buttons to frame
return1.pack(pady=(0,30),padx=30)
twoPlayers.pack(pady=(0,10),padx=30)
#Two player mode
class TwoPlayer(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
def makeform(field1):
for field in field1:
row = tk.Frame()
lab = tk.Label(row, width=15, text=field, anchor='w')
ent = tk.Entry(row)
row.pack(side="top", padx=5, pady=5)
lab.pack(side="left")
ent.pack(side="right")
names.append((field, ent))
return names
if __name__ == ("__init__"):
ents = makeform(field1)
b1 = tk.Button(text='Show',
command=lambda: controller.show_frame(StartPage))
b1.pack(padx=5, pady=5)
app = Yugioh_backEnd()
app.mainloop()

Categories

Resources