tkinter can not display the image - python-3.x

I want to put an image(light.gif) in the button of tkinter.
However, the image is not shown and only a small transparent box appears at the specified position.
My Code is
from tkinter import* #To use Tkinter
from tkinter import ttk #To use Tkinter
from tkinter import messagebox #To use Tkinter
import tkinter.font # To use Font
win = Tk()
win.title("Main Control")
win.geometry('450x400+100+300')
win.resizable(0,0)
def a1():
a1 = Toplevel()
a1.title("a1")
a1.geometry('450x350+560+100')
a1.resizable(0,0)
lignt_sensor_image=PhotoImage(file = 'light.gif')
light_sensor_button=Button(a1,width=15,height=8)
light_sensor_button.place=(x=275,y=200)
a1.mainloop()
newa1 = Button(win, text='A1', font=font1, command=a1, height = 5, width = 10)
newa1.place(x=50, y=30)
win.mainloop()
Please help me

You must keep a reference to the image; as it is created in a function, it was destroyed the moment the function exited.
There also were typos in your code that prevented it from running.
The following shows your image in the popup window.
import tkinter as tk
from tkinter import PhotoImage
def spawn_toplever_a1():
global light_sensor_image # <- hold the image in the global variable, so it persists
a1 = tk.Toplevel() # do not name your variables the same as your function
a1.title("a1")
a1.geometry('450x350+560+100')
light_sensor_image = PhotoImage(file='light.gif')
light_sensor_button = tk.Button(a1, image=light_sensor_image, text="my image", compound="center")
light_sensor_button.place(x=275,y=100) # <-- typo - removed '=' sign
# <-- removed call to mainloop
light_sensor_image = None # declare variable to hold the image
win = tk.Tk()
win.title("Main Control")
win.geometry('450x400+100+300')
win.resizable(0,0)
newa1 = tk.Button(win, text='A1', command=spawn_toplever_a1, height = 5, width = 10)
newa1.place(x=50, y=30)
win.mainloop()

Related

how to display a timer in python

hey i am making a program which records desktop screen.
So what i want to do is when ever i click on my start button(tkinter Gui) in my gui window.
It should start a timer like 3.... ,2.... ,1.... in big font directly on my desktop screen and not on my tkinter window. and then my function should start.
How can i do that ..
import tkinter as tk
from tkinter import *
root = Tk()
root.title("our program")
start_cap =tk.button(text='start recording' command=start_capute)
start_cap.pack()
root.mainloop()
Not mentioning the functions and the entire code here as not necessary the code is working fine and i just want to add a new feature of the timer in it.
An minimal example:
import tkinter as tk
# from tkinter import *
def Start():
def Count(Number):
if Number == -1:
win.withdraw()
print("Start") # what you want to do
return False
NumberLabel["text"] = Number
win.after(1000,Count,Number-1)
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
win = tk.Toplevel()
win.geometry("+%d+%d"%((screen_width-win.winfo_width())/2,(screen_height-win.winfo_height())/2)) # make it in the center.
win.overrideredirect(1)
win.wm_attributes('-topmost',1) # top window
win.wm_attributes('-transparentcolor',win['bg']) # background transparent.
NumberLabel = tk.Label(win,font=("",40,"bold"),fg='white')
NumberLabel.pack()
win.after(0,lambda :Count(3))
win.mainloop()
root = tk.Tk()
root.title("our program")
start_cap = tk.Button(text='start recording',command=Start)
start_cap.pack()
root.mainloop()

Why can't run both tkinter mainloop and cefpython3 messageloop?

I'm working at a project in Python3 in which i have both tkinter and a frame in tkinter with cef browser.
This is the code.
from tkinter import messagebox
#import threading
from cefpython3 import cefpython as cef
import platform
import sys
from tkinter import *
import time
def on_closing ():
print('closing')
r.destroy()
cef.Shutdown()
r = Tk()
r.geometry('800x600')
r.protocol('WM_DELETE_WINDOW', on_closing)
f = Frame(r, bg = 'blue', height = 200)
f.pack(side = TOP, fill = 'x')
g=Frame(r,bg = 'white',height = 200)
g.pack(side = TOP, fill = 'x')
b1 = Button (g,text='Exit',command = on_closing)
b1.pack (side = LEFT)
b2 = Button (g,text='Show something',command = lambda:messagebox.showinfo('TITLE', 'Shown something'))
b2.pack (side = RIGHT)
sys.excepthook = cef.ExceptHook
rect = [0, 0, 800, 200]
print('browser: ', rect[2],'x',rect[3])
window_info=cef.WindowInfo(f.winfo_id())
window_info.SetAsChild(f.winfo_id(),rect)
cef.Initialize()
browser = cef.CreateBrowserSync(window_info, url='http://www.google.com')
r.update()
cef.MessageLoop()
##_thread = threading.Thread(target=cef.MessageLoop)
##
##_thread.start()
##
##_thread.join()
r.mainloop()
print('end')
The problem is:
I leave cef.MessageLoop() and the browser works but buttons don't.
I comment out cef.MessageLoop() and the browser doesn't work but
tkinter window does.
I was thinking that maybe threading module wuold help but i tried (you can see the commented lines) and doesn't work (i get no exceptions but browser don't work).
How can i sort this out?
Tkinter runs in a single thread so when you write what is basically an infinite loop inside of it then you will block Tkinter from working. The only reason you screen is coming up at all is because you used update() but that will not fix the issue here.
The solution will be to use threading to manage the MessageLoop in a separate thread while also passing the frame to the function to allow for some interaction between Tkinter and cef.
Note: I also cleaned up your code a bit to better follow PEP8 standards.
import tkinter as tk
from tkinter import messagebox
from cefpython3 import cefpython as cef
import threading
import sys
def test_thread(frame):
sys.excepthook = cef.ExceptHook
window_info = cef.WindowInfo(frame.winfo_id())
window_info.SetAsChild(frame.winfo_id(), rect)
cef.Initialize()
browser = cef.CreateBrowserSync(window_info, url='http://www.google.com')
cef.MessageLoop()
def on_closing():
print('closing')
root.destroy()
root = tk.Tk()
root.geometry('800x600')
root.protocol('WM_DELETE_WINDOW', on_closing)
frame = tk.Frame(root, bg='blue', height=200)
frame2 = tk.Frame(root, bg='white', height=200)
frame.pack(side='top', fill='x')
frame2.pack(side='top', fill='x')
tk.Button(frame2, text='Exit', command=on_closing).pack(side='left')
tk.Button(frame2, text='Show something',
command=lambda: messagebox.showinfo('TITLE', 'Shown something')).pack(side='right')
rect = [0, 0, 800, 200]
print('browser: ', rect[2], 'x', rect[3])
thread = threading.Thread(target=test_thread, args=(frame,))
thread.start()
root.mainloop()
Results:

Trouble adding Images into a Gui using tkinter

OK so i am trying to make a program that displays an image when pressing a button, and i am having trouble getting the images into the program
this is my full code:
# Nicolas Bart
import tkinter as tk
from PIL import Image, ImageTk
from tkinter import *
window = tk.Tk()
window.title('Bad Meme Generator')
window.geometry('500x500')
window.configure(bg='saddle brown')
meme_label = tk.Label(window, text='PRESS BUTTON FOR BAD MEMES:',
fg='blue4', bg='brown4', font=('comicsans', '20'))
meme_label.grid(pady=25, padx=25, column=0, row=0)
def button_command():
meme_window = tk.Tk()
meme_window.title('I Warned You')
meme_window.grid()
image = Image.open('pexels-photo-247932.jpg')
photo = ImageTk.PhotoImage(image)
label = tk.Label(meme_window, image=photo)
label.image = photo
label.place(x = 0, y = 0)
button = tk.Button(window, text='Dont Do It!', command=button_command,
padx=100, pady=75, font=('comicsans', '20'),
bg='brown4', fg='blue4')
button.grid(column=0, row=1)
warning_label = tk.Label(window, text="Really shit tier memes incoming:",
bg='brown4', fg='blue4',
font=('comicsans', '20'))
warning_label.grid(pady=75)
window.mainloop()
every time i run this program, when i press the button to open the image, it gives the error "AttributeError: type object 'Image' has no attribute 'open'"
the specific part of the program that is giving the error is:
def button_command():
meme_window = tk.Tk()
meme_window.title('I Warned You')
meme_window.grid()
image = Image.open('pexels-photo-247932.jpg')
photo = ImageTk.PhotoImage(image)
label = tk.Label(meme_window, image=photo)
label.image = photo
label.place(x = 0, y = 0)
any help would be appreciated. Thank you :)
This is a good example of why you shouldn't do from tkinter import *. Tkinter has an Image class, so by doing this import after importing Image from PIL you overwrite the PIL class with the tkinter class.
Since you're already importing tkinter the preferred way (import tkinter as tk), you don't need to import tkinter a second time. You need to remove the statement from tkinter import *.
You also make the mistake of creating more than one instance of Tk. I don't know if it contributes to the problem or not, but it's not something you should be doing. If you need additional windows then you should create instances of Toplevel.

okay so I created this code to create a GUI but i need to add buttons and when ever i try it creates a new window. what should I do?

this is my code so far o cant add buttons with out it creating more windows
////////
#import tkinter
import tkinter
#import tkmessagebox(buttons)
from tkinter import *
#create a new window
window = tkinter.Tk()
#title <------ put it before .mainloop
window.title("yeahh boiiii")
#window size
window.geometry("500x500")
#set a window icon
window.iconbitmap('N:\downloads\icon.ico.ico')#<---- 8bit file name
master = Tk()
def callback():
print ("click!")
b = Button(master, text="OK", command=callback)
b.pack()
#draws the window
window.mainloop()
////////
please help
Your problem is that you create 2 instances of Tk(). This is a bad idea, and you don't need to do it since you can make your button a child of the window object:
# Import tkinter
import tkinter as tk
# Create a new window
window = tk.Tk()
# Title <------ put it before .mainloop
window.title("yeahh boiiii")
# Window size
window.geometry("500x500")
# Set a window icon
window.iconbitmap('N:\downloads\icon.ico.ico') #<---- 8bit file name
def callback():
print ("click!")
b = tk.Button(window, text="OK", command=callback)
b.pack()
# Draw the window
window.mainloop()
I also rewrote your tkinter import, because you were importing it twice...

How to run a python tkinter app without appearing in unity panel or alt-tab

I am working on a countdown timer for Ubuntu using Python and tkinter.
I have created most of the parts and now I want my app to be able run without appearing in Unity panel or Alt-Tab switching sequence. Is there any way to do this?
And also I'd like to whether it is possible to create a moveable window without the title bar. I tried root.overrideredirect(1).
But with it I am unable to move the window.
Here's the code for my program.
#!/usr/bin/python3
import tkinter as tk
from tkinter import ttk
from tkinter import TOP,LEFT
import time
import datetime
import sys
class Countdown(ttk.Frame):
def __init__(self,parent=None, endDate=None):
ttk.Frame.__init__(self,parent)
self.style = ttk.Style()
self.style.theme_use("clam")
self.pack()
endDate = endDate.split("/")
self.endTime = datetime.datetime(int(endDate[2]),int(endDate[1]),int(endDate[0]))
self.setWidgets()
self.initWidgets()
def setWidgets(self):
self.dLbl = ttk.Label(self,text="0",font="Ubuntu 14 bold")
self.dLbl.pack(padx=10,pady=10,side=LEFT)
self.hLbl = ttk.Label(self,text="0",font="Ubuntu 14 bold")
self.hLbl.pack(padx=10,pady=10,side=LEFT)
self.mLbl = ttk.Label(self,text="0",font="Ubuntu 14 bold")
self.mLbl.pack(padx=10,pady=10,side=LEFT)
def getTimeDelta(self):
self.curDate = datetime.datetime.now()
self.diff = self.endTime - self.curDate
self.tSec = self.diff.total_seconds()
self.days = self.diff.days
h = int(((self.tSec) - self.days*24*60*60)/3600)
self.hours = h if h>0 else 0
m = int(((self.tSec) - (self.hours*60*60+self.days*24*60*60))/60)
self.minutes = m if m>0 else 0
self.sec = int(self.tSec - self.minutes*60)
return [self.days,self.hours,self.minutes+1]
def initWidgets(self):
def set():
dhm = self.getTimeDelta()
self.dLbl["text"]=str(dhm[0])+" Days"
self.hLbl["text"]=str(dhm[1])+" Hours"
self.mLbl["text"]=str(dhm[2])+" Mins"
self.after(1000,set)
set()
root = tk.Tk()
root.title(sys.argv[1])
app = Countdown(root, sys.argv[2])
app.mainloop()
To move a window without borders you can take a look at this question for a simple example of how to implement what you want and just keep building on top of it.
For the hiding, you could use .iconify(), theoretically minimizing the app to the tray thus hiding it, and .deiconify(), for example:
root = tk.Tk()
root.iconify()
ps. If it don't work on Ubuntu/Unity you may have to use other GUI framework with support for this behavior on Ubuntu, like GTK.
import tkinter
root = tkinter.Tk()
root.withdraw()
root.mainloop()
Will hide the window.
Make your own titlebar, like so:
import sys
import tkinter as tk
import tkinter.ttk as ttk
root = tk.Tk() #create the window
titlebar = tk.Label(root,height=2, bg='cyan', fg='navyblue', text=sys.argv[0]) #create the titlebar
resizable = ttk.Sizegrip(root) #make the window resizable
titlebar.pack(fill='both') # display the titlebar
root.overrideredirect(1) #make the window run without appearing in alt tab
#root.withdraw()
#root.deiconify()
root.geometry('200x200') #set the window size to 200x200
resizable.pack(fill='y',side='right')
def ontitlebarclicked(event):
global lastposition
lastposition=[event.x,event.y]
def ontitlebardragged(event):
global lastposition
windowposition=[int(i) for i in root.geometry().split('+')[1:]] # get the window position
diffposition=[event.x-lastposition[0],event.y-lastposition[1]]
widthheight=root.geometry().split('+')[0]
root.geometry(widthheight+'+'+str(windowposition[0]+diffposition[0])+'+'+str(windowposition[1]+diffposition[1]))
titlebar.bind('<Button-1>',ontitlebarclicked)
titlebar.bind('<Button1-Motion>',ontitlebardragged)
titlebar.focus_force()

Resources