-
Notifications
You must be signed in to change notification settings - Fork 1.8k
[Question] How to take a screenshot using only tkinter? #5208
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
|
The "fallback" position for this is likely to be a pip installable If the I'm trying to find solutions that are as seamless and "simple" as possible. Ideally would be nice to not have to install the extra stuff, but it may be necessary. PyPI is turning out to be much better at application distribution than I was aware of. It was only after @Chr0nicT wrote the |
|
It looks like all the libraries using Pillow to handle the image. No idea to work it with only tkinter for
|
|
I ran the Demo_Graph_Drawing_And_Dragging_Figures.py demo program, which was touted to perform screen captures, but Evidently, cross-platform screen manipulation is a "hard computer science problem", and Pillow, like others, don't have the resources for platforms which only make up < 10% of the computer market (despite having the flashiest ads). |
|
I updated a couple of demo programs recently that do screencaptures. I state right at the top that it's Window-only, so there's the platform dependent problem that was hit right away. In this case it was because of my use of win32gui to get the bounding box for the window. https://github.com/PySimpleGUI/PySimpleGUI/blob/master/DemoPrograms/Demo_Save_Any_Window_As_Image.py |
|
I'm used to being in the minority (I once had a 512K "Fat Mac" in the 80's...) and understand how projects will put their resources where they have the most benefit, so I'm not "dinging" PSG as much as just bemoaning the state of the world... |
|
I think I can get you some limited Mac-specific code that doesn't require Pillow (but does something similar, so I guess I'd have to credit them for it). I have not tested it with multiple monitors yet (although I have two) so I'd need to hone it a bit before publication. Let me know if you are interested and I'lll look into it tomorrow... |
|
Lemme thinking ab... YES! Yes is the answer! Of course I'm interested! |
|
OK, I'll look into it tomorrow. BTW: I got Demo_Graph_Drawing_And_Dragging_Figures.py to not crash on my Mac by simply changing the output filename from "test.jpg" to "test.png". However, just to show Pillow's shortcomings, here are: |
|
This doesn't usually happen, but I got lucky this time: it turns out that the Mac (filetype changed from '.py' to '.txt' so GitHub would accept it here) And some example output of an element and the whole window: |
|
You may want to hold up a minute on using my code... |
|
I had a feeling I would see a warning 😉 I've got these kinds of constants in a number of the window-oriented code like this. I'm usually pretty OK with "Good Enough", but will take "Even Better" when it's available. Thank you very much for the help. Another area that I'm looking at is how to get the bounding box for the Windows. I'm using win32gui on Windows. @Chr0nicT is doing some research on other solutions. If you've got suggestions, I'm all ears.
|
|
As far as getting screen co-ords for another program's window goes, this is difficult in the Mac world without |
You can force a garbage collect using the technique found here: Basically import gc
# Then later when you want to force a garbage collect
gc.collect()It's not clear why the framebuffer would have old information in it if you're not seeing it also on your screen. Tanay has been making progress on Linux too so it's coming together better than expected. I'm sure there will be some fudging going on with the window size, etc, It'll be much better than nothing at all. I'm also going to have a "drag to capture" so that a manual screenshot can happen. |
|
I think I have a handle on this, and it is not a
And there's the rub: the I need to let Why this only appears to be an issue for non-titled windows is beyond me, but I suspect |
|
Call |
|
I was wondering if maybe the OS needs to run in order to reset the screen buffer, as well as |
|
Well, I dislike inserting a timed sleep (even if it is short), but here is an updated version. You may wish to check out how I got the main |
|
This is what I wrote up for Mac using AppleScript. Unsure if it works on Retina displays. I suppose ImageGrab could be swapped for the screencapture command as well. (Nothing pretty about it, hardcoded for 'Terminal'. In a specific app, I could change the code around to grab a specific window, of course) import subprocess
from PIL import ImageGrab
def get_all_windows():
"""
Solely for testing purposes.
:return: string of open window titles seperated by newlines.
"""
cmd = """osascript -s 's' -e 'tell application "System Events"
set processList to get the name of every process whose background only is false
end tell
return processList'"""
ret = subprocess.check_output(cmd, shell=True).decode(encoding='utf-8').replace('"', '').replace(", ", "\n").replace('{', '').replace('}', '').strip()
return ret
def capture_image(window_title):
"""
Captures screenshot using PIL imagegrab from a Window.
"""
cmd = """on run {arg1}
set win_title to arg1
try
tell application arg1
set win_bounds to get bounds of first window
end tell
end try
return win_bounds
end run"""
proc = subprocess.Popen(['osascript', '-', window_title], stdin=subprocess.PIPE, stdout=subprocess.PIPE, encoding='utf-8')
ret, err = proc.communicate(cmd)
if not err:
bnd_res = ret.replace(", ", ",")
geom = bnd_res.split(',')
arg1 = int(geom[0])
arg2 = int(geom[1])
arg3 = int(geom[2])
arg4 = int(geom[3])
print(f"Capturing BBOX: {arg1}, {arg2}, {arg3}, {arg4}")
im = ImageGrab.grab(bbox=(arg1, arg2, arg3, arg4))
im.save('test.png')
print(f"-------\nList of windows:\n{get_all_windows()}\n-------")
capture_image("Terminal") |
I'm with you on this. Rather than sleep, if it's the mainthread, then I use a Another technique would be to use a thread that does the sleep. Here's a short example of using a thread to sleep for 2 seconds. import PySimpleGUI as sg
import time
def sleep_thread(window:sg.Window):
time.sleep(2)
# If you want to explicitly send an event use this
# window.write_event_value('-SLEEP DONE-', None)
layout = [[sg.T('Sleep test')],
[sg.Button('Sleep'), sg.Button('Exit')]]
window = sg.Window('Window Title', layout, finalize=True)
while True:
event, values = window.read()
print(event, values)
if event == sg.WIN_CLOSED or event == 'Exit':
break
if event == 'Sleep':
window.perform_long_operation(lambda: sleep_thread(window), '-THEAD DONE-')
elif event == '-THEAD DONE-':
sg.popup('Sleep compeleted')
window.close() |
|
@Chr0nicT I like your mechanism for getting a list of windows, although it does list apps which are not actually visible when the command is run. But see my first post in this thread on why Here is what your code actually captured: Also, it created a blank .png when the Terminal window was located on my second monitor. BTW: |
|
@PySimpleGUI I have updated to the timed read and it appears to work. |
|
FYI: after I submitted a bug report to Pillow, they have created a PR to fix the issue with |
|
I really appreciate you pushing all this forward Bob! I'll be returning to this project shortly. I tooks a bit of a detour with the new scrollbar work. Sometimes the roadmap of features takes a sudden detour. I really appreciate all the help you've provided! |














Type of Issue (Enhancement, Error, Bug, Question)
Question
Environment
Operating System
Windows version 10
PySimpleGUI Port (tkinter, Qt, Wx, Web)
tkinter
Versions
Python version (
sg.sys.version)3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)]
PySimpleGUI Version (
sg.__version__)4.57.0.1
GUI Version (tkinter (
sg.tclversion_detailed), PySide2, WxPython, Remi)8.6.6
Your Experience In Months or Years (optional)
4 Years 3 months Python programming experience
Several Years Programming experience overall
Have not used another Python GUI Framework except for PySimpleGUI
Troubleshooting
These items may solve your problem. Please check those you've done by changing - [ ] to - [X]
Detailed Description
Adding the new "Gallery" feature to the PySimpleGUI project. There is a way of capturing a window in the Demo Program Demo_Graph_Drawing_And_Dragging_Figures_2_Windows.py, but it uses the PIL package. The idea is for PySimpleGUI to have this capability built right into the package so that you can get a screenshot of your application using a single keystroke or a function call.
I've looked around a bit and haven't come up with a tkinter-only solution, so turning to our awesome and talented community (and Jason of course ;-)
Code To Duplicate
Screenshot, Sketch, or Drawing
Whatcha Makin?
A gallery feature so that users can easily capture and upload their awesome creations for us all to marvel at!
The text was updated successfully, but these errors were encountered: