I wrote application in pygtk, that display a popup (like from Chrome) window, without resizing and moving option. All is great except one thing. I have to move this window to bottom of the screen, little above the taskbar.
Taskbar on MS windows has, on windows XP 30px, but on windows 7 is higher
I have the monitor / screen resolution getting by code:
w = self.get_screen()
print w.get_height()
but i still don't have a height of taskbar. Any ideas how to get this height?
On Windows you can use this:
from ctypes import windll, wintypes, byref
SPI_GETWORKAREA = 48
SM_CYSCREEN = 1
def get_taskbar_size():
SystemParametersInfo = windll.user32.SystemParametersInfoA
work_area = wintypes.RECT()
if (SystemParametersInfo(SPI_GETWORKAREA, 0, byref(work_area), 0)):
GetSystemMetrics = windll.user32.GetSystemMetrics
return GetSystemMetrics(SM_CYSCREEN) - work_area.bottom
print get_taskbar_size() # 30
Note that get_taskbar_size will return None if the API call failed.
Related
I am trying to build a program which gets me an enlarged photo of the text I want, for this I decided to use tkinter, win32gui and pygetwindow modules after taking some tips from already asked problems on stack overflow am having the following problems:
(1)I don't know how to get the hwnd value of the tkinter window which I created.
(2)I can't get hwnd value even if I know how to get it as the window is created after the complete code has run.
So please suggest me solutions to the problem
This is my code:
from tkinter import *
import win32gui
import pygetwindow as gw
#making the tkinter window
root = Tk()
root.title('DaysLeft')
#getting all the windows with their hwnd values
hwnd=gw.getAllWindows()
print(hwnd)
win32gui.SetForegroundWindow(hwnd)
bbox = win32gui.GetWindowRect(hwnd)
img = ImageGrab.grab(bbox)
img.show()
mainloop()
The above code gives error below as expected:.
line 26, in <module>
win32gui.SetForegroundWindow(hwnd)
TypeError: The object is not a PyHANDLE object
You can use PIL for taking a screenshot and win32gui or pygetwindow to get windows location.
Install PIL by saying
pip install Pillow
then your working code would be:
from tkinter import *
from win32gui import FindWindow, GetWindowRect
import pygetwindow as gw
from PIL import ImageGrab
def ss():
win = gw.getWindowsWithTitle('DaysLeft')[0]
winleft = win.left+9
wintop = win.top+38 #change 38 to 7 to not capture the titlebar
winright = win.right-9
winbottom = win.bottom-9
final_rect = (winleft,wintop,winright,winbottom)
img = ImageGrab.grab(final_rect)
img.save('Required Image.png')
#making the tkinter window
root = Tk()
root.title('DaysLeft')
root.after(3000,ss)
root.mainloop()
Why am i subtracting some amount from the pixels? its because, windows has decorations like drop shadow effect to the windows, which are also part of the windows and will be included in the screenshot, so i used this to get rid of those extra pixels.
Or if your still reluctant on using win32gui then, change the function to:
from win32gui import FindWindow, GetWindowRect
from PIL import ImageGrab
......
def ss():
win = FindWindow(None, 'DaysLeft')
rect = GetWindowRect(win)
list_rect = list(rect)
list_frame = [-9, -38, 9, 9] #change -38 to -7 to not capture the titlebar
final_rect = tuple((map(lambda x,y:x-y,list_rect,list_frame))) #subtracting two lists
img = ImageGrab.grab(bbox=final_rect)
img.save('Image.png')
What is after method? It just calls the function after 3000 ms, i.e, 3 seconds. We are basically giving the system some time to build the GUI and capture screenshot.
Hope it helped, do let me know if any errors or doubts.
Cheers
I wish to take screenshot of python tkinter window (NOT the entire computer scrren). I applied following codes:
import pyautogui
import tkinter as tk
root= tk.Tk()
# Define tkinter window
canvas1 = tk.Canvas(root, width = 300, height = 300)
canvas1.pack()
# Define fuction to take screenshot
def takeScreenshot ():
myScreenshot = pyautogui.screenshot()
myScreenshot.save('screenshot.png')
# Define fuction to take screenshot
myButton = tk.Button(text='Take Screenshot', command=takeScreenshot, bg='green',fg='white',font= 10)
canvas1.create_window(150, 150, window=myButton)
root.mainloop()
I wish to grab screenshot of only the window defined by "tk.Canvas(root, width = 300, height = 300)"
But, I am capturing the entire screren.
Can somebody please let me know how do we go about this in python ?
You can get the region of the canvas and pass them to screenshot():
def takeScreenshot():
# get the region of the canvas
x, y = canvas1.winfo_rootx(), canvas1.winfo_rooty()
w, h = canvas1.winfo_width(), canvas1.winfo_height()
pyautogui.screenshot('screenshot.png', region=(x, y, w, h))
Since you are on windows you should be able to employ the win32 API,
Contrary to this you could use more simple solutions such as PyScreenshot
Take the following code for example:
from pyscreenshot import grab
im = grab(bbox=(100, 200, 300, 400))
im.show()
“
As you can see you can use bbox to take screenshot that is at co-ordinates (100, 200) and has a width of 300 and a height of 400.
This would require you knowing the position of the windows before hand- which you can do in Tkinter I believe.”
I found this information from previous SO questions. Here is another snippet that may help you.
Here's how you can do it using PIL on win32. Given a window handle (hwnd), you should only need the last 4 lines of code. The preceding simply search for a window with "firefox" in the title. Since PIL's source is available, you should be able to poke around the ImageGrab.grab(bbox) method and figure out the win32 code you need to make this happen.
from PIL import ImageGrab
import win32gui
toplist, winlist = [], []
def enum_cb(hwnd, results):
winlist.append((hwnd, win32gui.GetWindowText(hwnd)))
win32gui.EnumWindows(enum_cb, toplist)
firefox = [(hwnd, title) for hwnd, title in winlist if 'firefox' in title.lower()]
# just grab the hwnd for first window matching firefox
firefox = firefox[0]
hwnd = firefox[0]
win32gui.SetForegroundWindow(hwnd)
bbox = win32gui.GetWindowRect(hwnd)
img = ImageGrab.grab(bbox)
img.show()
Suggestions I found include:
How to do a screenshot of a tkinter application?
How to Get a Window or Fullscreen Screenshot in Python 3k? (without PIL)
I hope this helps, sometimes all it takes is a good google search. If this help you please select this as the correct answer
Edit
Depending upon the contents of the window you could use this- if it is a drawing.
“ You can either generate a postscript document (to feed into some other tool: ImageMagick, Ghostscript, etc)”
from Tkinter import *
root = Tk()
cv = Canvas(root)
cv.create_rectangle(10,10,50,50)
cv.pack()
root.mainloop()
cv.update()
cv.postscript(file="file_name.ps", colormode='color')
root.mainloop()
Look at this if you are trying to save a drawing https://www.daniweb.com/programming/software-development/code/216929/saving-a-tkinter-canvas-drawing-python
You would need to define the rectangle for the screenshot
instead of myScreenshot = pyautogui.screenshot()
use the following in place of it:
myScreenshot = pyautogui.screenshot(region=(0,0, 300, 400))
The 4 points describe where you want the screenshot
https://pyautogui.readthedocs.io/en/latest/screenshot.html
How to disable title bar transparency for my own application (to create a solid title bar) in Windows 7 with Python Tkinter?
I'm not talking about changing the theme of Windows 7. I'm asking if I'm using the default windows 7 theme, which show title bar with some level of transparency, allowing to see a fuzzy image of the background. Now I'm creating a Python GUI application with Python Tkinter, for this particular application I don't want such transparency. I want a totally solid title bar. What shall I do in my Python code? I know that there are some applications which are able to do that.
The attached image show two applications. The above one is an application I installed on my computer. It has a solid title bar (I didn't change the theme) which is what I want. The second one is the application I created with Python Tkinter with transparent title bar under the same theme, which behaves similar to most of the applications, but is not what I want .
It's impossible with tkinter alone.
Sure, tkinter provides some options like an icon, a title, a child-toplevel, a tool window, etc, but don't be fooled by these options!
While he has an interface to communicate with window manager, he's mainly a tool for the client area of the window, and window managment/decoration isn't his purpose.
Operating with the Aero stuff is more complicated thing, than a trivial window styling, and it handled by the DWM, which can be controlled via the DWM composition API(1, 2).
For all that interaction we need the ctypes library (comes with python) and a set of the WinAPI functions:
DwmIsCompositionEnabled - to check if the Aero is enabled (system-wide).
DwmSetWindowAttribute - to specify (enable/disable) the non-client area rendering policy (and therefore revert to the Basic/Aero frame).
GetParent - to get a hwnd of the owner window, because we're trying to make changes in the non-client area.
Try to run this piece of code:
import ctypes as ct
import tkinter as tk
class App(tk.Tk):
is_composition_enabled = ct.windll.dwmapi.DwmIsCompositionEnabled
set_window_attribute = ct.windll.dwmapi.DwmSetWindowAttribute
get_parent = ct.windll.user32.GetParent
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.state = True
self.minsize(width=250, height=100)
self.frame = tk.Frame(self)
self.frame.pack(expand=True, fill='both')
self.status_label = tk.Label(self.frame)
self.status_label.pack(expand=True, fill='both')
self.populate_status_label()
self.toggle_button = tk.Button(self.frame, text='Toggle glass', command=self.toggle_glass)
self.toggle_button.pack(fill='x')
def populate_status_label(self):
status = 'en' if self.state else 'dis'
self.status_label.configure(text='Glass border %sabled!' % status)
def toggle_glass(self):
response = self.handle_glass()
if response:
self.state = not self.state
self.populate_status_label()
else:
print('Something bad happened!')
def handle_glass(self):
try:
composition_enabled = ct.c_bool()
response = not bool(self.is_composition_enabled(ct.byref(composition_enabled)))
if response and composition_enabled.value:
hwnd = self.get_parent(self.winfo_id())
switch_to_disable, switch_to_enable, rendering_policy = 1, 2, 2
dwma_ncrendering_switch = ct.c_int(switch_to_disable if self.state else switch_to_enable)
return not bool(self.set_window_attribute(hwnd, rendering_policy, ct.byref(dwma_ncrendering_switch),
ct.sizeof(dwma_ncrendering_switch)))
except AttributeError:
return False
app = App()
app.mainloop()
As a result, you should get something similar to this:
However, if your goal is to only disable a border transparency, while maintaining a same aero-like style, there's not much you can do about it.
I have a little problem with the following code. It creates a GtkWindow, make it paintable so I can draw on it with cairo on draw events. Then I add a GtkHeaderBar and a simple button widget.
from gi.repository import Gtk
import cairo
def draw_callback(widget,cr):
if widget.transparency:
cr.set_source_rgba(0,0,0,0.5)
else:
cr.set_source_rgb(0,0,0)
cr.set_operator(cairo.OPERATOR_SOURCE)
cr.paint()
cr.set_operator(cairo.OPERATOR_OVER)
win= Gtk.Window()
win.connect('delete-event', Gtk.main_quit)
win.set_app_paintable(True)
screen = win.get_screen()
visual = screen.get_rgba_visual()
win.transparency = False
if visual and screen.is_composited():
win.set_visual(visual)
win.transparency = True
else:
print('System doesn\'t support transparency')
win.set_visual(screen.get_system_visual)
win.connect('draw', draw_callback)
win.add(Gtk.Button(label='test'))
bar = Gtk.HeaderBar(title='title')
bar.set_has_subtitle(False)
bar.set_show_close_button(True)
win.set_titlebar(bar)
win.show_all()
Gtk.main()
The draw_callback paint the window background but this background looks like this :
It is like the cairo context doesn't have the same size of the window. The part that is draw and that is outside the window doesn't seems to answer to mouse event ( I cannot grab the window from this part for example)
If I don't use an HeaderBar, I don't have this problem.
This works with ruby 2.2 and the Gtk3 bindings.
My python Version is python 3 and the up to date Gtk modules
Edit:
Problem still exist with :
def size_allocation_cb(widget, rectangle):
widget.x = rectangle.x
widget.y = rectangle.y
widget.width = rectangle.width
widget.height = rectangle.height
win.connect('size-allocate', size_allocation_cb)
def draw_callback(widget,cr):
if widget.transparency:
cr.set_source_rgba(0,0,0,0.5)
else:
cr.set_source_rgb(0,0,0)
cr.set_operator(cairo.OPERATOR_SOURCE)
cr.rectangle(widget.x, widget.y, widget.width, widget.height)
cr.fill()
cr.set_operator(cairo.OPERATOR_OVER)
When you have a header bar, your window is drawn entirely on the client side, including shadows (for some reason). You will need to call cairo_rectangle() or some other function, preferably with the size allocation (not size request!) of the child of the GtkWindow, to clip cairo_paint() to the correct size.
Using pyGtk I created a window without decoration. The Window is hidden from task bar and top of all windows. On linux it works fine, but on MS Windows window sometimes it hides under some other window and always has "python.exe" the taskbar in windows.
Image representing my problem:
How can I hide this "python.exe" window from taskbar?
My code:
class Infowindow(gtk.Window):
'''
Klasa okienka informacyjnego
'''
def __init__(self, json, index, destroy_cb, device):
gtk.Window.__init__(self)
self.size_x = 260+48
self.size_y = 85
self.separator_size = 10
self.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_SPLASHSCREEN)
self.set_decorated(False)
self.set_property('skip-taskbar-hint', True)
self.set_opacity(1)
self.set_keep_above(True)
self.add_events(gtk.gdk.BUTTON_PRESS_MASK)
self.connect("enter-notify-event", self.__on_hover)
self.connect("leave-notify-event", self.__on_leave)
self.connect("button_press_event", self.__on_click)
self.set_size_request(self.size_x, self.size_y)
color = gtk.gdk.color_parse('#f3f3f3')
self.modify_bg(gtk.STATE_NORMAL, color)
self.expanded = False
self.index = index
self.destroy_cb = destroy_cb
self.json = json['data']
self.system_info = False if 'system' not in self.json or not self.json['system'] else True
self.device = device
f = gtk.Frame()
self.move_window(index) #move window to specified place
self.box_area = gtk.VBox()
self.box_area.set_spacing(10)
f.add(self.box_area)
self.add(f)
self.show_all()
Again thanks David Heffernan. Works perfect!
For people who want a full solution in python.
Name your windowin a characteristic way for example: 'alamakota'
Use find_window('alamakota'),
With given handler use hide_from_taskbar(handler)
Last use set_topmost(handler)
Window is hidden from taskbar and it's alwoays on top.
I know it's not a beatyfull code, but works fine on windows XP and above.
import ctypes
import win32gui
import win32api
from win32con import SWP_NOMOVE
from win32con import SWP_NOSIZE
from win32con import SW_HIDE
from win32con import SW_SHOW
from win32con import HWND_TOPMOST
from win32con import GWL_EXSTYLE
from win32con import WS_EX_TOOLWINDOW
#staticmethod
def find_window(name):
try:
return win32gui.FindWindow(None, name)
except win32gui.error:
print("Error while finding the window")
return None
#staticmethod
def hide_from_taskbar(hw):
try:
win32gui.ShowWindow(hw, SW_HIDE)
win32gui.SetWindowLong(hw, GWL_EXSTYLE,win32gui.GetWindowLong(hw, GWL_EXSTYLE)| WS_EX_TOOLWINDOW);
win32gui.ShowWindow(hw, SW_SHOW);
except win32gui.error:
print("Error while hiding the window")
return None
#staticmethod
def set_topmost(hw):
try:
win32gui.SetWindowPos(hw, HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE)
except win32gui.error:
print("Error while move window on top")
You have two options to remove a window from the taskbar:
Add the WS_EX_TOOLWINDOW extended window style. But this has other consequences and I cannot say whether or not they are serious.
Give the window an owner that is not visible. This allows you freedom to use whatever window styles and extended styles you wish, but does involve more work.
It's natural that your window will go beneath other windows. That's how windows works. If you want to make your window appear on top, show it with HWND_TOPMOST.
I've no idea how any of this is (or is not) implemented under PyGtk. I've just given you the Win32 answer!
Win32 solution provided in the other answer is not very easy and it does not play well with the GtkWindow::show method. A simple solution now in Gtk3 is:
win->set_type_hint(Gdk::WindowTypeHint::WINDOW_TYPE_HINT_UTILITY); //This works
win->set_skip_taskbar_hint(); //This does not guarantee to work