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).
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.
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.
able frame in tkinter, the frame consist of multiple mini long canvases(which contain some text and a button)which can be scrolled up and down with a scrollbar. I also used tkinter themes to make my gui look nice. But for some reason as soon as i added in the gui, the frame would lag abit when scrolled up and down, like the canvases are crashing into eachother, is their away to fix this?
Here is how it looks without scrolling
Here's how it looks sometimes, when its scrolled
Here's the code
from tkinter import *
from ttkthemes.themed_tk import ThemedTk
from tkinter import *
from tkinter.ttk import *
import tkinter as tk
from tkinter import ttk
class tkinterprogram(ThemedTk):
def __init__(self, *args, **kwargs):
ThemedTk.__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 (StartPage,Task):
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()
frame.winfo_toplevel().geometry("1024x720")
class StartPage(tk.Frame):
def __init__(self, parent, controller):
ttk.Frame.__init__(self, parent)
l = Canvas(self, bg='#4A4949')
l.pack(fill='both', expand='True')
global canvascon
canvascon = Canvas(l, height=400,width=1500,bg='#4A4949',highlightthickness=0)
global frame2
frame2 = Frame(canvascon)
global myscrollbar
myscrollbar = Scrollbar(l, orient="vertical",command=canvascon.yview)
canvascon.create_window((0, 0), window=frame2,width=15000,anchor='nw')
canvascon.place(x=25,y=150,relheight=0.558,relwidth=0.87)
myscrollbar.pack(side=RIGHT, fill=Y,pady=25)
Button(l,text='go',command=lambda: meth()).pack()
def meth():
for count in range(25):
c = Canvas(frame2, height=50, bg="#1E2133",highlightthickness=5,highlightbackground='#4A4949')
lab = tk.Label(frame2, text='running',bg='#1E2133',fg='#EFEFEF')
lab_window = c.create_window(10,15, window=lab,anchor=tk.NW)
stop = tk.Button(frame2, text='STOP')
stop_window = c.create_window(200, 15, window=stop, anchor=tk.NW)
c.pack(fill=X,expand=True)
frame2.update() # update frame2 height so it's no longer 0 ( height is 0 when it has just been created )
canvascon.configure(yscrollcommand=myscrollbar.set, scrollregion="0 0 0 %s" % frame2.winfo_height())
class Task(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
app = tkinterprogram()
app.get_themes()
app.set_theme('scidgrey')
app.mainloop()
Thanks for any help in advance.
I am new to Python and not very experienced with classes, however working on the creation of a tkinter GUI for data processing right now.
As many time consuming processes are happening in the background not visible for the user, I would like to insert a progress-bar that shows the current progress between 0 and 100 as Progress and the processing step Action in the main window
Right now, I have problems to access the bar parameters (value and label/name) outside of the class when the code is doing the data processing in a different function.
Below is a working example of the GUI in Python 3.7
import time
import tkinter as tk
from tkinter import ttk
def ProcessingScript():
### UpdateProgressbar(50, 'Halfway there') ###
time.sleep(2)
print('Processing takes place here')
### UpdateProgressbar(75, 'Finishing up') ###
time.sleep(2)
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self, width=500, height=500)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.geometry("500x500")
self.frames = {}
frame = ProcessingPage(container, self)
self.frames[ProcessingPage] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(ProcessingPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class ProcessingPage(tk.Frame):
def __init__(self, parent, controller, ):
tk.Frame.__init__(self, parent)
self.controller = controller
def PlotData():
UpdateProgressbar(10, 'Generating...')
# Execute Main Plotting Function here
ProcessingScript()
UpdateProgressbar(100, 'Finished Plot')
def UpdateProgressbar(Progress, Action):
progressLabel = tk.Label(self, text=Action).place(x=20, y=440)
progressBar['value'] = Progress
progressBar = ttk.Progressbar(self, orient="horizontal", length=200,mode="determinate")
progressBar.place(x=20, y=470)
progressBar['value'] = 0
progressLabel = tk.Label(self, text='Idle...').place(x=20, y=440)
PlotButton = tk.Button(self, text='Plot Data',command= PlotData)
PlotButton.place(x=20, y=320)
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
In this example, the ProcessingScript function would be in a different file and as an ideal outcome I would like to be able to call the UpdateProgressbar function from anywhere in my other scripts to update the bar.
Note: I am aware that a function inside the __init__ function is not best practice, however I was not able to get it running in any other way as I found no way to connect the results of the UpdateProgressbar function with the progressBar created.
Any help to achieve this and exclude UpdateProgressbar from __init__ is much appreciated.
EDIT:
Below is a working version based on the input from the comments. It might now be very pretty but is currently doing what I expect it do to. Please let me know if you see some possibilities for improvement.
app.update() has to be called after each change in the progress bar to show the error and old labels are deleted with self.progressLabel.destroy().
timeit.sleep() is simply a way of showing the changes and will not be part of the final code.
import time
import tkinter as tk
from tkinter import ttk
def ProcessingScript(self, callback):
ProcessingPage.UpdateProgressbar(self, 50, 'Halfway there')
time.sleep(2)
print('Processing takes place here')
ProcessingPage.UpdateProgressbar(self, 75, 'Finishing up')
time.sleep(2)
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self, width=500, height=500)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.geometry("500x500")
self.frames = {}
frame = ProcessingPage(container, self)
self.frames[ProcessingPage] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(ProcessingPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class ProcessingPage(tk.Frame):
def __init__(self, parent, controller, ):
tk.Frame.__init__(self, parent)
self.controller = controller
progressBar = ttk.Progressbar(self, orient="horizontal", length=200,mode="determinate")
progressBar.place(x=20, y=470)
progressBar['value'] = 0
self.progressLabel = tk.Label(self, text='Idle...')
self.progressLabel.place(x=20, y=440)
PlotButton = tk.Button(self, text='Plot Data',command= self.PlotData)
PlotButton.place(x=20, y=320)
def PlotData(self):
self.UpdateProgressbar(10, 'Generating...')
app.update()
time.sleep(2)
# Execute Main Plotting Function here
ProcessingScript(self, self.UpdateProgressbar)
self.UpdateProgressbar(100, 'Finished Plot')
app.update()
def UpdateProgressbar(self, Progress, Action):
self.progressLabel.destroy()
self.progressLabel = tk.Label(self, text=Action)
self.progressLabel.place(x=20, y=440)
progressBar = ttk.Progressbar(self, orient="horizontal", length=200,mode="determinate")
progressBar.place(x=20, y=470)
progressBar['value'] = Progress
app.update()
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
I want to show two images successively like a slideshow in my stacked tkinter frame. I heard, that I can do that with the after-method, but how do I use this method? Sorry if my english is bad. Thanks.
# -*- coding: cp1252 -*-
import sys
import Tkinter as tk
from Tkinter import *
from functools import partial
import random
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title("test")
self.state('zoomed')
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 (fenster, mode1):
frame= F(container, self)
self.frames[F]=frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(fenster)
def show_frame(self, c):
frame=self.frames[c]
frame.tkraise()
class fenster(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label=tk.Label(self, text="Das ist die Startseite")
label.pack()
button=tk.Button(self, text="Start",
command=lambda: controller.show_frame(mode1))
button.pack()
class mode1(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label1=tk.Label(self, text=" ")
label1.pack()
def ok(label1):
def do_a():
image1 = PhotoImage(file = 'test.gif')
photo1=Label(image=image1)
photo1.image=image1
photo1.pack()
image2 = PhotoImage(file = 'tet.gif')
photo2=Label(image=image2)
photo2.image=image2
photo2.pack()
def do_b():
print("ngfijnwgfekö")
WORDS={"test1":do_a,
"test2":do_b}
choice=random.choice(list(WORDS))
label1['text']=choice
WORDS[choice]()
button1=tk.Button(self, text='Knopf', command=partial(ok, label1))
button1.pack()
if __name__== "__main__":
app=SampleApp()
app.mainloop()
Not sure where you want to add the slide show to your code, so here's a minimal working example of a simple Tkinter GUI, using after to cycle though all the images found in the current directory.
from Tkinter import Tk, PhotoImage, Label
from glob import glob
from itertools import cycle
# this method calls itself again after 1000 milliseconds
def show_next():
image.configure(file=next(images))
root.after(1000, show_next)
# cycle though gif images found in working directory
images = cycle(glob("*.gif"))
# build minimal test GUI
root = Tk()
image = PhotoImage()
Label(root, image=image).pack()
# start slide show and GUI main loop
show_next()
root.mainloop()