I am new to python and am trying to create an application that displays different information like a clock, current news, notice board etc.
I got the clock to work however I am encountering a few bugs. One is that a smaller window launches when the application does. I thought this was something to do with the self.root = tk.Tk() in the initialisation however doing anything to this line produces errors.
The other bug is that while the background image (0.png) used to fill up the entire screen as it is the same size as my monitor, when I added the clock to the application, the image is shifted to the bottom right of the screen, leaving a small white line to the top and left of the screen. I have tried to fix this by messing with the panel.pack changing it to grid and place however both of this did nothing to the lines. I feel like something is overwriting this line.
None of these bugs are showing up in the console and I don't know what to do. Here is the code I am running:
from tkinter import *
from PIL import ImageTk, Image
import os
import time
import tkinter as tk
class App(Tk):
def __init__(self):
self.root = tk.Tk()
self.label = tk.Label(text="",font=('comic',50,'bold'),bg = '#464545',fg = '#1681BE')
self.label.place(height = 206,width = 487, x = 1384, y = 824)
self.update_clock()
self.root.mainloop()
def update_clock(self):
now = time.strftime('%H:%M:%S')
self.label.configure(text=now)
self.root.after(1000, self.update_clock)
root = Tk()
img = ImageTk.PhotoImage(Image.open("0.png"))
panel = Label(root, image = img)
panel.pack()
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.overrideredirect(1)
app = App()
root.geometry("%dx%d+0+0" % (w, h))
root.mainloop()
I hope someone can find what's wrong with it because I certainly can't!
Since your App class inherit from Tk, you don't need to create another root window. So I gathered all your code inside the App class. When I use an image the side of my screen, I don't see any line at the top or at the left of the screen, so I hope it will work for you as well.
from PIL import ImageTk, Image
import os
import time
import tkinter as tk
class App(tk.Tk):
def __init__(self):
# call the __init__ method of Tk class to create the main window
tk.Tk.__init__(self)
# background image
img = ImageTk.PhotoImage(Image.open("0.png"))
panel = Label(self, image=img)
panel.pack()
# clock
self.label = tk.Label(self, text="", font=('comic',50,'bold'),
bg='#464545', fg='#1681BE')
self.label.place(height=206, width=487, x=1384, y=824)
self.update_clock()
# window geometry
w, h = self.winfo_screenwidth(), self.winfo_screenheight()
self.geometry("%dx%d+0+0" % (w, h))
self.overrideredirect(True)
self.mainloop()
def update_clock(self):
now = time.strftime('%H:%M:%S')
self.label.configure(text=now)
self.after(1000, self.update_clock)
app = App()
Related
I am doing a painting program where one can draw things, change the background color and save it as a file on the computer. Everything works except that changing the background color takes way too much time.
This is the code:
from tkinter import *
import tkinter.filedialog as tk
from tkinter import Menu
from tkinter.colorchooser import askcolor
from tkinter.filedialog import asksaveasfile,askopenfilename
import os
from PIL import Image as im
from PIL import ImageTk,ImageDraw,ImageColor
class P:
x=y=None
image=None
my_image=im.new("RGB",(600,600),(255,255,255))
draw=ImageDraw.Draw(my_image)
def __init__(self,window):
self.window = window
self.upper_frame = Frame(window)
self.upper_frame.grid(row=0,column=0, padx=10, pady=5,sticky="ew")
self.lower_frame = Frame(window)
self.lower_frame.grid(row=2, column=0, padx=10, pady=5,sticky="ew")
self.canvas= Canvas(self.lower_frame,width=700,height=530,bg="white")
self.canvas.grid()
self.bg = Button(self.upper_frame,text="Background",command= self.bgcolor) #change bg color
self.bg.grid(row=2,column=1,padx=(100,10))
self.upper_menu()
def bgcolor(self):
chosen_color = askcolor(color=self.canvas["bg"])[1]
self.canvas.configure(bg=chosen_color)
color_RGB = ImageColor.getcolor(chosen_color, "RGB")
img = self.my_image
for i in range(0,600):#pixels in width
for j in range(0,600): #height = 600 pix
data = img.getpixel((i,j)) #gives color of pixel
if (data[0]==255 and data[1]==255 and data[2]==255): #data represent RGB color
img.putpixel((i,j),color_RGB) #changes pixel color
def save_pic(self,event=None): #save image on comp.
my_file=asksaveasfile(mode="w",defaultextension=".png",filetypes=[("png files","*.png")],
initialdir="/home/b/",parent=window)
if my_file is not None:
path=os.path.abspath(my_file.name)
self.my_image.save(path)
def upper_menu(self):
self.menubar = Menu(window)
self.menu1 = Menu(self.menubar, tearoff=0)
self.menu1.add_command(label="Save pic", command=self.save_pic)
self.menu1.add_separator()
self.menu1.add_command(label="Exit", command=window.destroy)
self.menubar.add_cascade(label="Settings", menu=self.menu1)
self.menu2 = Menu(self.menubar, tearoff=0)
self.window.config(menu=self.menubar)
window = Tk()
window.geometry("720x590")
p = P(window)
window.mainloop()
I use the method bgcolor to change the background. How to make it work faster?
I suspect the problem is with calling putpixel 360,000 times. Instead, try creating the color data in the loop and then call putdata once after the loops have finished.
I'm not overly familiar with PIL, but this makes a huge difference when doing similar things with the tkinter PhotoImage class: doing one pixel at a time is slow, doing an array of pixels is fast.
I am making a GUI program using Raspberry Pi.
This GUI is made with Tkinter and works only on the touch screen, no mouse and keyboard.
However, the arrow buttons on the COMBOBOX are too small to touch with your fingers.
I used "tkinter.font" to increase the font size, but the font size only increases and the arrow buttons do not increase in size.
How can I increase the size of this arrow button?
How to apply a style doesn't work. My code is below. please help me
import tkinter.ttk
import tkinter.font
class Application:
def __init__(self, parent):
self.parent = parent
self.data = [1,2,3]
self.bigfont = tkinter.font.Font(family="Helvetica",size=30)
root.option_add("*TCombobox*Listbox*Font", self.bigfont)
self.combo()
def combo(self):
self.style = tkinter.ttk.Style()
self.style.configure('W.TCombobox', arrowsize = 1000)
self.cBox = tkinter.ttk.Combobox(self.parent, values = self.data, style = 'W.TCombobox', font=self.bigfont)
self.cBox.current(0)
self.cBox.pack()
if __name__ == '__main__':
root = tkinter.Tk()
root.title("COMBOBOX TEST")
root.geometry("640x400+100+100")
app = Application(root)
root.mainloop()
I am doing a people counter in raspberry pi. I want to display an one image if someone comes in, and another one if someone comes out. Right now i am using the code below (that i took from another question here xd) to change the image that tkinter is displaying. The problem with this is thay it only shows the picture cat.jpg for a second, and then it shows a black screen and nothing happends.
import sys
if sys.version_info[0] == 2: # the tkinter library changed it's name from Python 2 to 3.
import Tkinter
tkinter = Tkinter #I decided to use a library reference to avoid potential naming conflicts with people's programs.
else:
import tkinter
from PIL import Image, ImageTk
import time
def updateRoot(root,imagen):
pilImage = Image.open(imagen)
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.overrideredirect(1)
root.geometry("%dx%d+0+0" % (w, h))
root.focus_set()
root.bind("<Escape>", lambda e: (e.widget.withdraw(), e.widget.quit()))
canvas = tkinter.Canvas(root,width=w,height=h)
canvas.pack()
canvas.configure(background='black')
imgWidth, imgHeight = pilImage.size
if imgWidth > w or imgHeight > h:
ratio = min(w/imgWidth, h/imgHeight)
imgWidth = int(imgWidth*ratio)
imgHeight = int(imgHeight*ratio)
pilImage = pilImage.resize((imgWidth,imgHeight), Image.ANTIALIAS)
image = ImageTk.PhotoImage(pilImage)
imagesprite = canvas.create_image(w/2,h/2,image=image)
root.update()
root = tkinter.Tk()
updateRoot(root,"Cat.jpg")
time.timesleep(5)
updateRoot(root,"Dog.jpg")
Before this I used this code
import tkinter
from PIL import Image, ImageTk
from tkinter import ttk
def updateRoot(root,imagen):
image1 = Image.open(imagen)
image2 = ImageTk. PhotoImage(image1)
image_label = ttk. Label(root , image =image2)
image_label.place(x = 0 , y = 0)
root.update()
That works fine, but it's not full screen.
First you should do the followings outside updateRoot():
make root window fullscreen (you can simply use root.attributes('-fullscreen', 1))
bind the <Escape> key
create the canvas and create_image() (you can use Label to do the same thing)
Then just update the image inside updateRoot().
Also you should use after() instead of time.sleep().
Below is an example:
try:
import Tkinter as tkinter
except:
import tkinter
from PIL import Image, ImageTk
def updateRoot(imagen):
# resize the image to fill the whole screen
pilImage = Image.open(imagen)
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
image = ImageTk.PhotoImage(pilImage.resize((w,h)))
# update the image
canvas.itemconfig(imgbox, image=image)
# need to keep a reference of the image, otherwise it will be garbage collected
canvas.image = image
root = tkinter.Tk()
root.attributes('-fullscreen', 1)
root.bind('<Escape>', lambda _: root.destroy())
canvas = tkinter.Canvas(root, highlightthickness=0)
canvas.pack(fill=tkinter.BOTH, expand=1)
imgbox = canvas.create_image(0, 0, image=None, anchor='nw')
# show the first image
updateRoot('Cat.jpg')
# change the image 5 seconds later
root.after(5000, updateRoot, 'Dog.jpg')
root.mainloop()
Fixed your Black issue using labels, try this. i think you still need to resize image to fit screen
import sys
if sys.version_info[0] == 2: # the tkinter library changed it's name from Python 2 to 3.
import Tkinter
tkinter = Tkinter #I decided to use a library reference to avoid potential naming conflicts with people's programs.
else:
import tkinter
from PIL import Image, ImageTk
import time
from tkinter import *
import PIL.Image
def updateRoot(root,imagen):
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.overrideredirect(1)
root.geometry("%dx%d+0+0" % (w, h))
root.focus_set()
root.bind("<Escape>", lambda e: (e.widget.withdraw(), e.widget.quit()))
img = PIL.Image.open(imagen)
root.tkimage = ImageTk.PhotoImage(img)
Label(root,image = root.tkimage).place(x=0, y=0, relwidth=1, relheight=1)
root.update()
root = tkinter.Tk()
updateRoot(root,"Cat.jpg")
time.sleep(3)
updateRoot(root,"Dog.jpg")
root.mainloop()
I am trying to place the image in the same window but it opens up in a new window and I can't figure out why. I've tried google but couldn't find anything to help me. How do I specify the image should be placed in the initial window that opens up instead of its own separate window?
import Tkinter as tk
import io
import base64
# Import the function for downloading web pages
from urllib import urlopen
# Import the regular expression function
from re import findall
# Import the Tkinter functions
from Tkinter import *
# Import Python's HTML parser
from HTMLParser import *
class MainWindow(tk.Frame):
root = tk.Tk()
def __init__(self, *args, **kwargs):
tk.Frame.__init__(self, *args, **kwargs)
def createimage(self):
# a little more than width and height of image
w = 520
h = 320
x = 80
y = 100
# use width x height + x_offset + y_offset (no spaces!)
# this GIF picture previously downloaded from tinypic.com
image_url = "http://i46.tinypic.com/r9oh0j.gif"
image_byt = urlopen(image_url).read()
image_b64 = base64.encodestring(image_byt)
self.photo = tk.PhotoImage(data=image_b64)
# create a white canvas
#topframe = Frame(root)
cv = tk.Canvas(bg='white')
cv.pack(side='top', expand='yes')
# put the image on the canvas with
# create_image(xpos, ypos, image, anchor)
cv.create_image(10, 10, image=self.photo, anchor='nw')
if __name__ == "__main__":
root = tk.Tk()
main = MainWindow(root)
root.geometry("400x300")
main.pack(side="top", fill="both", expand=True)
main.createimage()
root.mainloop()
1. Why does it open up in a separate window?
You need to pass a master to each constructor. This should be the widget (Tk, Frame, Toplevel, Canvas, ...) that the new widget should be placed inside. Like this:
tk.Canvas(master = self, g='white')
tk.PhotoImage(master = self, data=image_b64)
When the master is destroyed, widgets with it as master are also destroyed.
2. In which window does it open up?
Tkinter has the default root, the first window which is created. This window is used for any widget you do not pass a master to.
i.e. the first root = tk.Tk()
I'm trying to show a jpg image as background for a GUI thing I'm building.
I can get it to work in a single method:
from Tkinter import *
from PIL import Image, ImageTk
class MakeGUI(object):
master = None
w = None
def __init__(self):
self.canvasSizeY = 400 #height
self.canvasSizeX = 640 #width
def setupCanvas(self):
"""
preps the canvas for drawing.
"""
self.master = Tk()
self.w = Canvas(self.master, width=self.canvasSizeX, height=self.canvasSizeY)
self.w.config(bg='white')
image = Image.open("background.jpg")
photo = ImageTk.PhotoImage(image)
self.w.create_image(0,0, image=photo, anchor=NW)
self.w.pack()
mainloop()
def main():
makeGUI = MakeGUI()
makeGUI.setupCanvas()
if __name__ == '__main__':
main()
But when I try and make the canvas in one method, and show the canvas in another, it doesn't show the jpg (when I've been testing, I've created and shown & text and rectangles using this approach):
from Tkinter import *
from PIL import Image, ImageTk
class MakeGUI(object):
master = None
w = None
def __init__(self):
self.canvasSizeY = 400 #height
self.canvasSizeX = 640 #width
def setupCanvas(self):
"""
preps the canvas for drawing.
"""
self.master = Tk()
self.w = Canvas(self.master, width=self.canvasSizeX, height=self.canvasSizeY)
self.w.config(bg='white')
image = Image.open("background.jpg")
photo = ImageTk.PhotoImage(image)
self.w.create_image(0,0, image=photo, anchor=NW)
def showImage(self):
"""
pushes the image to the screen
"""
self.w.pack()
self.w.mainloop()
def main():
makeGUI = MakeGUI()
makeGUI.setupCanvas()
if __name__ == '__main__':
main()
I want to use the GUI dynamically to show some text as I work through some editing, so I'm interested to understand what I've got wrong before I get too far into the build in case its a showstopper...
The most obvious problem is that in the second case you are never calling showImage. Even after you do call that function, your image probably won't show up. Images will be garbage-collected if there isn't a reference to them. It may seem like there's a reference because you're adding it to a canvas, but that isn't enough.
You'll need to do something like:
self.photo = ImageTk.PhotoImage(image)
Finally, I recommend that you take the call to mainloop out of showImage. mainloop must always be called exactly once, so most typically it is the last line of code in your program, or the last line of code in your main function.
A more common way to make a Tkinter application is to subclass either the Tk object or a Frame object, rather than having your main application be a generic object. For example:
class MyApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
...
self.setupCanvas(...)
...
if __name__ == "__main__":
app = MyApp()
app.mainloop()