I am trying to take a screen shot of a GUI window generated by tkinter, but when I take a screen shot I only get the desktop and not the Python window.
I read with the new o/s Catalina you have to give the terminal permissions, which I have done but still I cannot grab the python window. Even if I do a full screen shot I still cannot see the Python window.
https://github.com/BoboTiG/python-mss/issues/134
I have tried several different ways, but still cannot get to screen grab the Python window.
Does any one else have these problems with Catalina O/S?
from PIL import Image, ImageTk
from tkinter import Tk, BOTH, Canvas, BOTH, NW, W
from tkinter.ttk import Frame, Label, Style
import pyscreenshot
import io
import os
import subprocess
import sys
import mss
top_border_height = 50
bottom_border_height = 70
screen_width = 800
screen_height = 480
video_icon_640x480_x = (800-640)/2
video_icon_640x480_y = (480-480)/2
homeicon64x64_x = 8
homeicon64x64_y = 8
root = Tk('test Screen')
root.geometry("800x480")
w = Canvas(root, width=screen_width, height=screen_height)
back_ground = ImageTk.PhotoImage(Image.open("./icon/wireframe_mode_background.png"))
w.create_image(0, 0, image=back_ground, anchor='nw')
w.video_icon_640x480 = ImageTk.PhotoImage(Image.open("./icon/wireframe_640x480.png"))
w.create_image(video_icon_640x480_x, video_icon_640x480_y, image=w.video_icon_640x480, anchor="nw")
w.home_icon_640x480 = ImageTk.PhotoImage(Image.open("./icon/wireframe_64x64.png"))
w.create_image(homeicon64x64_x,homeicon64x64_y,image=w.home_icon_640x480, anchor="nw")
w.video_icon_640x480_1 = ImageTk.PhotoImage(Image.open("./icon/wireframe_64x64.png"))
w.create_image(728,8,image=w.video_icon_640x480_1, anchor="nw")
w.video_icon_640x480_2 = ImageTk.PhotoImage(Image.open("./icon/wireframe_64x64.png"))
w.create_image(728,80,image=w.video_icon_640x480_2, anchor="nw")
w.pack()
root.mainloop()
im = pyscreenshot.grab(bbox=(10, 10, 510, 510)) # X1,Y1,X2,Y2
im.save('screenshot.png')
with mss.mss() as sct:
filename = sct.shot(mon=-1, output='fullscreen.png')
print(filename)
The answer lies in the Python release (or maybe Pillow) setting up the needed resource when on MacOS so the permission is requested when not available. Until that happens, each user of the code / application will have to enable the Python Launcher to have the Screen Recording permission added since Catalina. I simply had to add this limitation / hiccup for MacOS users to my applications' user manual for now User Manual Screenshot. I have made a separate, specific question about this at Can you request the MacOS Screen Recording permission in Python
If this changes or you know a way to request an OS permission from within a Python application, please let us know. The comment above about answering a similar question is not valid. It is not addressing this very specific MacOS permission issue added since Catalina. (I do not have enough points to comment on the comment but could answer the question; go figure.)
Related
A friend and I are making a game in pygame. We would like to have a pygame window embedded into a tkinter or WxPython frame, so that we can include text input, buttons, and dropdown menus that are supported by WX or Tkinter. I have scoured the internet for an answer, but all I have found are people asking the same question, none of these have been well answered.
What would be the best way implement a pygame display embedded into a tkinter or WX frame? (TKinter is preferable)
Any other way in which these features can be included alongside a pygame display would also work.
(Note this solution does not work on Windows systems with Pygame 2.
See Using 'SDL_WINDOWID' does not embed pygame display correctly into another application #1574. You can currently download older versions of Pygame here.)
According to this SO question and the accepted answer, the simplest way to do this would be to use an SDL drawing frame.
This code is the work of SO user Alex Sallons.
import os
import pygame
import Tkinter as tk
from Tkinter import *
root = tk.Tk()
embed = tk.Frame(root, width = 500, height = 500) #creates embed frame for pygame window
embed.grid(columnspan = (600), rowspan = 500) # Adds grid
embed.pack(side = LEFT) #packs window to the left
buttonwin = tk.Frame(root, width = 75, height = 500)
buttonwin.pack(side = LEFT)
os.environ['SDL_WINDOWID'] = str(embed.winfo_id())
os.environ['SDL_VIDEODRIVER'] = 'windib'
screen = pygame.display.set_mode((500,500))
screen.fill(pygame.Color(255,255,255))
pygame.display.init()
pygame.display.update()
def draw():
pygame.draw.circle(screen, (0,0,0), (250,250), 125)
pygame.display.update()
button1 = Button(buttonwin,text = 'Draw', command=draw)
button1.pack(side=LEFT)
root.update()
while True:
pygame.display.update()
root.update()
This code is cross-platform, as long as the windib SDL_VIDEODRIVER line is omitted on non Windows systems. I would suggest
# [...]
import platform
if platform.system == "Windows":
os.environ['SDL_VIDEODRIVER'] = 'windib'
# [...]
Here are some links.
For embedding in WxPython An Article on pygame.org
For Embedding in WxPython An Article on the WxPython wiki
For embedding in Tkinter see this SO question
Basically, there are many approaches.
On Linux, you can easily embed any application in a frame inside another. Simple.
Direct Pygame output to a WkPython Canvas
Some research will provide the relevant code.
According to the tracebacks, the program crashes due to TclErrors. These are caused by attempting to access the same file, socket, or similar resource in two different threads at the same time. In this case, I believe it is a conflict of screen resources within threads. However, this is not, in fact, due to an internal issue that arises with two gui programs that are meant to function autonomously. The errors are a product of a separate thread calling root.update() when it doesn't need to because the main thread has taken over. This is stopped simply by making the thread call root.update() only when the main thread is not doing so.
A friend and I are making a game in pygame. We would like to have a pygame window embedded into a tkinter or WxPython frame, so that we can include text input, buttons, and dropdown menus that are supported by WX or Tkinter. I have scoured the internet for an answer, but all I have found are people asking the same question, none of these have been well answered.
What would be the best way implement a pygame display embedded into a tkinter or WX frame? (TKinter is preferable)
Any other way in which these features can be included alongside a pygame display would also work.
(Note this solution does not work on Windows systems with Pygame 2.
See Using 'SDL_WINDOWID' does not embed pygame display correctly into another application #1574. You can currently download older versions of Pygame here.)
According to this SO question and the accepted answer, the simplest way to do this would be to use an SDL drawing frame.
This code is the work of SO user Alex Sallons.
import os
import pygame
import Tkinter as tk
from Tkinter import *
root = tk.Tk()
embed = tk.Frame(root, width = 500, height = 500) #creates embed frame for pygame window
embed.grid(columnspan = (600), rowspan = 500) # Adds grid
embed.pack(side = LEFT) #packs window to the left
buttonwin = tk.Frame(root, width = 75, height = 500)
buttonwin.pack(side = LEFT)
os.environ['SDL_WINDOWID'] = str(embed.winfo_id())
os.environ['SDL_VIDEODRIVER'] = 'windib'
screen = pygame.display.set_mode((500,500))
screen.fill(pygame.Color(255,255,255))
pygame.display.init()
pygame.display.update()
def draw():
pygame.draw.circle(screen, (0,0,0), (250,250), 125)
pygame.display.update()
button1 = Button(buttonwin,text = 'Draw', command=draw)
button1.pack(side=LEFT)
root.update()
while True:
pygame.display.update()
root.update()
This code is cross-platform, as long as the windib SDL_VIDEODRIVER line is omitted on non Windows systems. I would suggest
# [...]
import platform
if platform.system == "Windows":
os.environ['SDL_VIDEODRIVER'] = 'windib'
# [...]
Here are some links.
For embedding in WxPython An Article on pygame.org
For Embedding in WxPython An Article on the WxPython wiki
For embedding in Tkinter see this SO question
Basically, there are many approaches.
On Linux, you can easily embed any application in a frame inside another. Simple.
Direct Pygame output to a WkPython Canvas
Some research will provide the relevant code.
According to the tracebacks, the program crashes due to TclErrors. These are caused by attempting to access the same file, socket, or similar resource in two different threads at the same time. In this case, I believe it is a conflict of screen resources within threads. However, this is not, in fact, due to an internal issue that arises with two gui programs that are meant to function autonomously. The errors are a product of a separate thread calling root.update() when it doesn't need to because the main thread has taken over. This is stopped simply by making the thread call root.update() only when the main thread is not doing so.
A friend and I are making a game in pygame. We would like to have a pygame window embedded into a tkinter or WxPython frame, so that we can include text input, buttons, and dropdown menus that are supported by WX or Tkinter. I have scoured the internet for an answer, but all I have found are people asking the same question, none of these have been well answered.
What would be the best way implement a pygame display embedded into a tkinter or WX frame? (TKinter is preferable)
Any other way in which these features can be included alongside a pygame display would also work.
(Note this solution does not work on Windows systems with Pygame 2.
See Using 'SDL_WINDOWID' does not embed pygame display correctly into another application #1574. You can currently download older versions of Pygame here.)
According to this SO question and the accepted answer, the simplest way to do this would be to use an SDL drawing frame.
This code is the work of SO user Alex Sallons.
import os
import pygame
import Tkinter as tk
from Tkinter import *
root = tk.Tk()
embed = tk.Frame(root, width = 500, height = 500) #creates embed frame for pygame window
embed.grid(columnspan = (600), rowspan = 500) # Adds grid
embed.pack(side = LEFT) #packs window to the left
buttonwin = tk.Frame(root, width = 75, height = 500)
buttonwin.pack(side = LEFT)
os.environ['SDL_WINDOWID'] = str(embed.winfo_id())
os.environ['SDL_VIDEODRIVER'] = 'windib'
screen = pygame.display.set_mode((500,500))
screen.fill(pygame.Color(255,255,255))
pygame.display.init()
pygame.display.update()
def draw():
pygame.draw.circle(screen, (0,0,0), (250,250), 125)
pygame.display.update()
button1 = Button(buttonwin,text = 'Draw', command=draw)
button1.pack(side=LEFT)
root.update()
while True:
pygame.display.update()
root.update()
This code is cross-platform, as long as the windib SDL_VIDEODRIVER line is omitted on non Windows systems. I would suggest
# [...]
import platform
if platform.system == "Windows":
os.environ['SDL_VIDEODRIVER'] = 'windib'
# [...]
Here are some links.
For embedding in WxPython An Article on pygame.org
For Embedding in WxPython An Article on the WxPython wiki
For embedding in Tkinter see this SO question
Basically, there are many approaches.
On Linux, you can easily embed any application in a frame inside another. Simple.
Direct Pygame output to a WkPython Canvas
Some research will provide the relevant code.
According to the tracebacks, the program crashes due to TclErrors. These are caused by attempting to access the same file, socket, or similar resource in two different threads at the same time. In this case, I believe it is a conflict of screen resources within threads. However, this is not, in fact, due to an internal issue that arises with two gui programs that are meant to function autonomously. The errors are a product of a separate thread calling root.update() when it doesn't need to because the main thread has taken over. This is stopped simply by making the thread call root.update() only when the main thread is not doing so.
I'd like to use some features from pygame (sprite graphics) in my GUI I made in Tkinter. I know of OcempGUI, but I'd prefer to stick to Tkinter, just use some modules from pygame. This is similar but not quite the same. Is this possible at all? What are potential problems (event loop)?
This works on Linux. If you're lucky, it might work on other operating systems as well.
import Tkinter as tk
import os
w, h = 500, 200
# Add a couple widgets. We're going to put pygame in `embed`.
root = tk.Tk()
embed = tk.Frame(root, width=w, height=h)
embed.pack()
text = tk.Button(root, text='Blah.')
text.pack()
# Tell pygame's SDL window which window ID to use
os.environ['SDL_WINDOWID'] = str(embed.winfo_id())
# The wxPython wiki says you might need the following line on Windows
# (http://wiki.wxpython.org/IntegratingPyGame).
#os.environ['SDL_VIDEODRIVER'] = 'windib'
# Show the window so it's assigned an ID.
root.update()
# Usual pygame initialization
import pygame as pg
pg.display.init()
screen = pg.display.set_mode((w,h))
pos = 0
while 1:
# Do some pygame stuff
screen.fill(pg.Color(0,0,0))
pos = (pos + 1) % screen.get_width()
pg.draw.circle(screen, pg.Color(255,255,255), (pos,100), 30)
# Update the pygame display
pg.display.flip()
# Update the Tk display
root.update()
I want to display an image to the user with PIL and when the user clicks anywhere on this image, I want a def onmousedown(x,y) to be called. I will do some extra stuff in this function. How can I do this in PIL?
Thanks,
PIL won't do it alone -- PIL is an image manipulation library with no User Interfaces - it does have a showmethod, which does open an external program which displays the image, but does not communicate back with the Python process.
Therefore, in order to be able to get a user to interact with an image, one does have to build a GUI program using one of the consolidated toolkits for use with Python - the better known ones are Tkinter, GTK and Qt4. Tkinter is interesting because it comes pre-installed with Windows Python installs, and therefore is more easily available for users of that system. Windows users would have to separately download and install gtk or qt libraries to be able to use your program if you decide to use on of the other toolkits.
Here is a minimalist example of a Tkinter application with a clickable image:
import Tkinter
from PIL import Image, ImageTk
from sys import argv
window = Tkinter.Tk(className="bla")
image = Image.open(argv[1] if len(argv) >=2 else "bla2.png")
canvas = Tkinter.Canvas(window, width=image.size[0], height=image.size[1])
canvas.pack()
image_tk = ImageTk.PhotoImage(image)
canvas.create_image(image.size[0]//2, image.size[1]//2, image=image_tk)
def callback(event):
print "clicked at: ", event.x, event.y
canvas.bind("<Button-1>", callback)
Tkinter.mainloop()
Here is another related post
How to display picture and get mouse click coordinate on it
On Ubuntu to install
sudo apt-get install python python-tk idle python-pmw python-imaging python-imaging-tk
Then it all works.
I added a resize to #jsbueno's solution and fixed one import issue.
import Tkinter
from PIL import ImageDraw, Image, ImageTk
import sys
window = Tkinter.Tk(className="bla")
image = Image.open(sys.argv[1] if len(sys.argv) >=2 else "bla2.png")
image = image.resize((1000, 800), Image.ANTIALIAS)
canvas = Tkinter.Canvas(window, width=image.size[0], height=image.size[1])
canvas.pack()
image_tk = ImageTk.PhotoImage(image)
canvas.create_image(image.size[0]//2, image.size[1]//2, image=image_tk)
def callback(event):
print "clicked at: ", event.x, event.y
canvas.bind("<Button-1>", callback)
Tkinter.mainloop()