Segmentation fault: 11 - not sure what it means, why it has happened. I thought it was an issue with Python on my machine by all other files run fine. I have, of course, tried restarting and re-installing Python but didn't help.
I'm just trying to implement frame switching via a menu bar with tkinter.
Any help greatly appreciated.
# import tkinter modules
from tkinter import *
from tkinter import ttk
import tkinter.font as tkFont
from PIL import ImageTk, Image
from tkcalendar import *
# import modules for restart functionality
import os
import sys
import time
# define self
class tkinterApp(Tk):
def __init__(self,*args, **kwargs):
Tk.__init__(self, *args, **kwargs)
# creating a container
container = Frame(self)
container.pack(side = "top", fill = "both", expand = True)
container.grid_rowconfigure(0, weight = 1)
container.grid_columnconfigure(0, weight = 1)
# initialising frames to an empty array
self.frames = {}
menu_bar = Menu(container)
menu_bar.add_cascade(label="Main Menu", menu=menu_bar)
menu_bar.add_command(label="Welcome page", command=lambda: self.show_frame(welcome_frame))
menu_bar.add_command(label="Book a vehicle", command=lambda: self.show_frame(booking_frame))
menu_bar.add_command(label="Register as new user", command=lambda: self.show_frame(register_frame))
Tk.config(self, menu=menu_bar)
for F in (welcome_frame, register_frame, booking_frame):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row = 0, column = 0, sticky = "nsew")
self.show_frame(welcome_frame)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class welcome_frame(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
# welcome_frame = Frame(self, width=1000, height=800)
# welcome_frame.grid()
welcome = Label(welcome_frame, text="Hello, please use the menu above to navigate the interface")
welcome.grid(row=0, column=4, padx=10, pady=10)
class register_frame(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
welcome = Label(self, text="New user - enter your details below to use the Collyer's car park.")
welcome.grid(row=0, column=4, padx=10, pady=10)
class booking_frame(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
app = tkinterApp()
app.geometry("1000x800")
app.mainloop()
You are trying to make a cascade menu where the cascaded menu is the same menu:
menu_bar.add_cascade(label="Main Menu", menu=menu_bar)
The menu option needs to point to a new menu menu.
main_menu = Menu(menu_bar)
menu_bar.add_cascade(label="Main Menu", menu=main_menu)
I'm guessing you also want to put the menu commands on that menu, too
main_menu.add_command(label="Book a vehicle", command=lambda: self.show_frame(booking_frame))
main_menu.add_command(label="Register as new user", command=lambda: self.show_frame(register_frame))
Unrelated to the question, this code is also wrong:
welcome = Label(welcome_frame, text="Hello, please use the menu above to navigate the interface")
You are trying to use a class as the parent/master of the Label widget. You can't do that. The first parameter needs to be a widget. In this case, it should be self.
You also need to make sure that show_frame is indented the same as the __init__ method of the tkinterApp class.
Related
I am new to python and GUI-Thinker. I'm learning about how to switch windows on GUI using Tkinker as UI, and python as a programming language.
I followed this guideline Switch between two frames in tkinter to switch frames in thinker and it worked.
Then, I'm trying to show widgets and hide all other widgets using bind("<<ComboboxSelected>>". But when I choose Monthly option, widgets as I set under DeleteOptions condition didn't show up. The same thing to Period option, widgets as I set under DeleteOptions condition didn't show up.
My Code:
from tkinter import *
import tkinter as tk
from tkinter import ttk
from tkinter import font as tkfont
from tkcalendar import DateEntry
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")
# the container is where we'll stack a bunch of frames
# on top of each other, then the one we want visible
# will be raised above the others
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 (StartPage, PageOne):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
# put all of the pages in the same location;
# the one on the top of the stacking order
# will be the one that is visible.
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is the start page", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button1 = tk.Button(self, text="Go to Page One",
command=lambda: controller.show_frame("PageOne"))
button1.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 1", font=controller.title_font)
label.grid()
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.grid()
def DeleteOptions():
if SVcmb_Delete.current()=="Monthly":
HideDeleteOptions()
lblMonthly.grid(row=4)
SVcmb_Monthly.grid(row=4, column=1)
if SVcmb_Delete.current()=="Period":
HideDeleteOptions()
lblFrom.grid(row=4)
txtFrom.grid(row=4, column=1)
lblTo.grid(row=5)
txtTo.grid(row=5, column=1)
lblSV_Search=tk.Label(self,text="Delete by")
lblSV_Search.grid(row=3)
SVcmb_Delete=ttk.Combobox(self,state="readonly",justify=CENTER,font=("times new roman",15))
SVcmb_Delete["values"]=("Select","Monthly","Period")
SVcmb_Delete.grid(row=3,column=1)
SVcmb_Delete.bind("<<ComboboxSelected>>", lambda event:DeleteOptions)
def HideDeleteOptions():
lblMonthly.grid_forget()
SVcmb_Monthly.grid_forget()
lblFrom.grid_forget()
txtFrom.grid_forget()
lblTo.grid_forget()
txtTo.grid_forget()
lblMonthly=tk.Label(self,text="Monthly")
SVcmb_Monthly=ttk.Combobox(self,state="readonly",values=[1,2,3],justify=CENTER)
lblFrom=tk.Label(self,text="From")
txtFrom=DateEntry(self,selectmode='day',date_pattern='mm/dd/y')
lblTo=tk.Label(self,text="To")
txtTo=DateEntry(self,selectmode='day',date_pattern='mm/dd/y')
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
On page one. I'm looking for a way like when I chose Monthly option, all widgets under DeleteOptions condition show up and all widgets of Period option are hidden as I set under DeleteOptions condition. The same thing to Period option, all widgets under DeleteOptions condition show up and all widgets of Monthly option are hidden as I set under DeleteOptions condition.
Please help me. Thank you so much.
There are two problems with your code. This first is with your lambda expression:
SVcmb_Delete.bind("<<ComboboxSelected>>", lambda event:DeleteOptions)
is wrong because it doesn't actually call the DeleteOptions() function the way it's written.
Instead, do it like this:
SVcmb_Delete.bind("<<ComboboxSelected>>", lambda event: DeleteOptions())
The second problem is with your use of the SVcmb_Delete.current() method in the DeleteOptions() function because it returns the index of the the current entry text, not the entry text itself. To obtain that, you should use the get() method. With that correction made the function should look like something like this:
def DeleteOptions():
if SVcmb_Delete.get() == "Monthly":
HideDeleteOptions()
lblMonthly.grid(row=4)
SVcmb_Monthly.grid(row=4, column=1)
if SVcmb_Delete.get() == "Period":
HideDeleteOptions()
lblFrom.grid(row=4)
txtFrom.grid(row=4, column=1)
lblTo.grid(row=5)
txtTo.grid(row=5, column=1)
Lastly I also strongly suggest that you read and start following the PEP 8 - Style Guide for Python Code to make your code more readable.
I copied Python code to create a Tkinter window with multiple frames. I put many kinds of widgets into it with no problem but when I add radiobuttons, those act funny, although they work fine in a regular window (without multiple pages). Whether I set the value or not, none of the radiobuttons are selected. What's worse, if I just pass the mouse pointer over a radiobutton, it looks like it gets selected although I didn't click it. If I pass the mouse pointer over both radiobuttons, they BOTH look selected, violating the one-of-many-selections rule of radiobuttons.
I should add that I tried this with a pack manager and with a grid manager. The results are the same.
Here's a stripped-down version of my code:
import tkinter as tk
class MainWindow(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# Set the title of the main window.
self.title('Multi-frame window')
# Set the size of the main window to 300x300 pixels.
self.geometry('300x100')
# This container contains all the pages.
container = tk.Frame(self)
container.grid(row=1, column=1)
self.frames = {} # These are pages to which we want to navigate.
# For each page...
for F in (StartPage, PageOne):
# ...create the page...
frame = F(container, self)
# ...store it in a frame...
self.frames[F] = frame
# ..and position the page in the container.
frame.grid(row=0, column=0, sticky='nsew')
# The first page is StartPage.
self.show_frame(StartPage)
def show_frame(self, name):
frame = self.frames[name]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text='Start Page')
label.grid(row=1, column=1)
# When the user clicks on this button, call the
# show_frame method to make PageOne appear.
button1 = tk.Button(self, text='Visit Page 1',
command=lambda : controller.show_frame(PageOne))
button1.grid(row=2, column=1)
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
# When the user clicks on this button, call the
# show_frame method to make StartPage appear.
button1 = tk.Button(self, text='Back to Start',
command=lambda : controller.show_frame(StartPage))
button1.grid(row=1, column=1)
options_label = tk.Label(self, text='Choose an option: ')
options_label.grid(row=2, column=1)
options_value = tk.IntVar()
first_option = tk.Radiobutton( self , text = 'Option 1' ,
variable = options_value , value = 1 )
second_option = tk.Radiobutton( self , text = 'Option 2' ,
variable = options_value , value = 2 )
first_option.grid(row=2, column=2)
second_option.grid(row=2, column=3)
options_value.set(1)
if __name__ == '__main__':
app = MainWindow()
app.mainloop()
The problem is that options_value is a local value that gets destroyed when __init__ finishes.
You need to save a reference to it, such as self.options_value.
I can't show up the Image in tkinter PIL class.
Image is packed or placed successfully but it is not showing up.
windowxp wall paper and a man's face are not shown.
I made message box when click his face.
So if I click the location, message box is showing up. But picture is not showing up. Just location :(
I use windows 64bit and Python 3.6
I am Korean. I'm not goot at English.... Please understand me.
Please help me
This is right display: screenshot
from tkinter import *
import tkinter as tk
from tkinter import messagebox
from PIL import Image, ImageTk
##함수
class Mainwindow(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title("김상곤이 좋아하는 꿈꾸는 학과 과목 문제 맞추기♡")
self.geometry("1600x900")
self.resizable(width=FALSE, height=FALSE)
wall = tk.PhotoImage(file="gif/bg.gif")
labelwall = tk.Label(self, image = wall)
labelwall.place(x=0, y=0)
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
def func_make():
messagebox.showinfo("제작자", "김재온, 정성윤, 안예진, 이소유, 우연서")
def func_exit():
window.quit()
window.destroy()
mainMenu=Menu(self)
fileMenu=Menu(mainMenu)
self.config(menu=mainMenu)
mainMenu.add_cascade(label="파일", menu=fileMenu)
fileMenu.add_command(label="제작자", command=func_make)
fileMenu.add_separator()
fileMenu.add_command(label="종료", command=func_exit)
self.frames={}
for F in (MainPage, QuizPage):
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("MainPage")
def show_frame(self, page_name):
frame = self.frames[page_name]
frame.tkraise()
def 국어():
page == 1
subject=['국어', '과학', '역사', '사회', '기술']
#색이나 위치 숫자 설정
mint="#99FFFF"
subjectsize=30
subjectbutton=60
##위젯
class MainPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller=controller
def clickksk(event):
messagebox.showinfo("김상곤", "아주 좋아요^^")
labeltitle=tk.Label(self, text=
"""김상곤이 좋아하는 꿈꾸는
학과 과목 문제 맞추기♡""", font=("궁서체", 35), bg="#8DFD73")
ksk=tk.PhotoImage(file="gif/ksk.gif")
labelksk=tk.Label(self, image=ksk)
labelksk.place(x=400-subjectbutton, y=200)
labelksk.bind("<Button>", clickksk)
labelhow=tk.Label(self, text="게임방법! ", font=("맑은 고딕", 30), bg="#FFE400")
labelexplain=tk.Label(self, text=
"""원하는 과목을 택해 클릭한후,
OX퀴즈를 풀면 됩니다^^
난이도=중3""", font=("고딕체", 25), bg="#FFE400")
btKorean=tk.Button(self, text="국어", font=("양재블럭체", subjectsize), bg=mint,
command=lambda: controller.show_frame("QuizPage"))
btScience=tk.Button(self, text="과학", font=("양재블럭체", subjectsize), bg=mint)
btHistory=tk.Button(self, text="역사", font=("양재블럭체", subjectsize), bg=mint)
btSocial=tk.Button(self, text="사회", font=("양재블럭체", subjectsize), bg=mint)
bttech=tk.Button(self, text="기술", font=("양재블럭체", subjectsize), bg=mint)
##pack하는 장소(코드 순차대로)
labeltitle.place(relx= 0.25, rely=0.02, relwidth=0.5)
labelhow.place(x=610-subjectbutton, y=200, relwidth=0.3)
labelexplain.place(x=610-subjectbutton, y=260, relwidth=0.3)
btKorean.place(x=400-subjectbutton, y=600)
btScience.place(x=600-subjectbutton, y=600)
btHistory.place(x=800-subjectbutton, y=600)
btSocial.place(x=1000-subjectbutton, y=600)
bttech.place(x=1200-subjectbutton, y=600)
btKorean.bind("<Button-1>")
btScience.bind("<Button-1>")
btHistory.bind("<Button-1>")
btSocial.bind("<Button-1>")
bttech.bind("<Button-1>")
class QuizPage(tk.Frame):
def __init__(self, parent, controller):
OB=PhotoImage(file="gif/OB.gif")
XR=PhotoImage(file="gif/XR.gif")
tk.Frame.__init__(self, parent)
self.controller = controller
buttonOB=Button(self, image=OB)
buttonXR=Button(self, image=XR)
buttonOB.place()
buttonXR.place()
if __name__ == "__main__":
app = Mainwindow()
app.mainloop()
I think your main problem is you are using two subclassed frames and using grid to manage them but the main application window is not expanding the grid area. You need to add the following to MainWindow.__init__:
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
so that the (0,0) cell is expanded to fill all the available space. Then your currently selected frame will expand into that region as it has sticky='NSWE' set in the grid method call.
Where you define container you are both packing and gridding. You have to only use one. However, this looks like dead code. Maybe you intended to put the subclassed frames into this container at one time.
Also, you cannot just call buttonXR.place(), you need to give it a position. For instance: buttonXR.place(x=1, y=1).
I'm aware of how to create a basic Tkinter menu bar, but I'm not sure how to implement it such that the menu appears on every frame of a multi-frame GUI.
I will be using the menu bar to switch between frames. Therefore, I need to run the controller.show_frame command within the menu commands. I am currently using buttons to do this.
I'm unable to find a way to do this, as (as far as I am aware) the menu must be created in the frame class rather than the tk.Tk class, in order to allow me to run the function.
Here is the code:
""" Messing about with tkinter """
import tkinter as tk
LARGE_FONT = ("Verdana", 12)
class Window(tk.Tk):
""" Main class """
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 frame in (Main, Checker):
current_frame = frame(container, self)
self.frames[frame] = current_frame
current_frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(Main)
def show_frame(self, cont):
""" Raises a particular frame, bringing it into view """
frame = self.frames[cont]
frame.tkraise()
def qprint(quick_print):
""" Function to print a string """
print(quick_print)
class Main(tk.Frame):
""" Main frame of program """
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Main Menu", font=LARGE_FONT)
label.pack(pady=10, padx=10)
class Checker(tk.Frame):
""" Password Strength Checker """
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Password Checker", font=LARGE_FONT)
label.pack(pady=10, padx=10)
APP = Window()
APP.geometry("350x200")
APP.mainloop()
"the menu must be created in the frame class rather than the tk.Tk class, in order to allow me to run the
function."
I don't think that's true, see below example that creates Menu for a Toplevel widget:
import tkinter as tk
if __name__ == '__main__':
root = tk.Tk()
root.withdraw()
toplevel = tk.Toplevel(root)
# create a toplevel menu
menubar = tk.Menu(toplevel)
menubar.add_command(label="Hello!")
menubar.add_command(label="Quit!", command=root.quit)
# display the menu
toplevel.config(menu=menubar)
root.mainloop()
Alternatively, you can create menu's in frames for their parents with the condition that their parent is Toplevel-like.
In below example when a menu item is selected Root's menu jumps between the Root's menu and its children FrameWithMenu object's menu:
import tkinter as tk
class Root(tk.Tk):
def __init__(self):
super().__init__()
self.title("The Root class with menu")
self.a_frame = FrameWithMenu(self)
self.create_menu()
def create_menu(self):
self.menubar = tk.Menu(self)
self.menubar.add_command(label="Root", command=self.a_frame.replace_menu)
self['menu'] = self.menubar
class FrameWithMenu(tk.Frame):
def __init__(self, master):
super().__init__(master)
def replace_menu(self):
""" Overwrite parent's menu if parent's class name is in _valid_cls_names.
"""
_parent_cls_name = type(self.master).__name__
_valid_cls_names = ("Tk", "Toplevel", "Root")
if _parent_cls_name in _valid_cls_names:
self.menubar = tk.Menu(self)
self.menubar.add_command(label="Frame", command=self.master.create_menu)
self.master['menu'] = self.menubar
if __name__ == '__main__':
root = Root()
root.mainloop()
I found an answer to my own question. All I needed to do was create the menu using the controller parameter, which references the tk.Tk class.
class Main(tk.Frame):
""" Main frame of program """
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Main Menu", font=LARGE_FONT)
label.pack(pady=10, padx=10)
menubar = tk.Menu(controller)
menubar.add_command(label="Checker", command=lambda: controller.show_frame(Checker))
controller.config(menu=menubar)
How would I create a new window when the user clicks a button (still needs creating)? I have took some code out to make this shorter. I need a button creating and when they hit that button, a new window opens. I haven't created the button because the button has to be linked to the new window. Please help
My imports...
class App:
def __init__(self, master):
self.master = master
# call start to initialize to create the UI elemets
self.start()
def start(self):
self.master.title("E-mail Extranalyser")
self.now = datetime.datetime.now()
tkinter.Label(
self.master, text=label01).grid(row=0, column=0, sticky=tkinter.W)
# CREATE A TEXTBOX
self.filelocation = tkinter.Entry(self.master)
self.filelocation["width"] = 60
self.filelocation.focus_set()
self.filelocation.grid(row=0, column=1)
# CREATE A BUTTON WITH "ASK TO OPEN A FILE"
# see: def browse_file(self)
self.open_file = tkinter.Button(
self.master, text="Browse...", command=self.browse_file)
# put it beside the filelocation textbox
self.open_file.grid(row=0, column=2)
# now for a button
self.submit = tkinter.Button(
self.master, text="Execute!", command=self.start_processing,
fg="red")
self.submit.grid(row=13, column=1, sticky=tkinter.W)
def start_processing(self):
#code here
def browse_file(self):
# put the result in self.filename
self.filename = filedialog.askopenfilename(title="Open a file...")
# this will set the text of the self.filelocation
self.filelocation.insert(0, self.filename)
root = tkinter.Tk()
app = App(root)
root.mainloop()
Use a Toplevel to open a new one. Modify your code as shown below.
self.NewWindow = tkinter.Button(self.master,
text="New Window",
command=self.CreateNewWindow)
def CreateNewWindow(self):
self.top = tkinter.Toplevel()
self.top.title("title")
Take a look at https://www.youtube.com/watch?v=jBUpjijYtCk. Working through this tutorial would probably help you but this specific video shows how to work with multiple pages.
Something like this:
from tkinter import *
class Sample(Tk):
def __init__(self,*args, **kwargs):
Tk.__init__(self, *args, **kwargs)
container = Frame(self)
container.pack(side="top", fill="both", expand = True)
self.frames = {}
for F in (MainPage, OtherPage):
frame=F(container, self)
self.frames[F]=frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(MainPage)
def show_frame(self, page):
frame = self.frames[page]
frame.tkraise()
class MainPage(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
Label(self, text="Start Page").pack()
Button(self, text="other page?", command=lambda:controller.show_frame(OtherPage)).pack()
class OtherPage(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
Label(self, text="Next Page").pack()
Button(self, text="back", command=lambda:controller.show_frame(MainPage)).pack()
app = Sample()
app.mainloop()