Is there a way to create transparent windows with Tkinter? - python

I'm trying, ultimately, to create "oddly-shaped windows" with Python using the Tkinter module. But for now I will settle for being able to make the background transparent while keeping child widgets fully-visible.
I'm aware this is done with wxPython and some other modules, but I'm inquiring as to the limits of Tkinter.
Can Tkinter create a clear Canvas or Frame? Can it pack UI elements without a canvas or frame? Can individual UI elements be transparent?
Can it pass mouse-click locations back to the system for processing any windows below it in the Z stack?

The option root.attributes('-alpha', 0.1) can be used to make a transparent window
from Tkinter import *
root = Tk()
root.attributes('-alpha', 0.3)
root.mainloop()
However in this case even the widgets on the root will inherit the transparency.
Update for Linux (Tested on Ubuntu)
The above code does not work on Linux machines. Here's an update that works on Linux.
from tkinter import Tk # or(from Tkinter import Tk) on Python 2.x
root = Tk()
root.wait_visibility(root)
root.wm_attributes('-alpha',0.3)
root.mainloop()
Not sure if this works on Windows.

Summary as of late 2019:
As of TCL/TK version 8.6, the alpha, fullscreen and topmost window attributes work on ALL platforms (Windows, Mac and Linux):
https://www.tcl.tk/man/tcl8.6/TkCmd/wm.htm#M9
Previous versions of the manual noted that there PREVIOUSLY WERE platform differences (only some platforms supported those 3 attributes). But as long as you use the latest TCL/TK, you're guaranteed that all of those attributes will work on ALL platforms!
There are still platform quirks on LINUX, since each window attribute feature relies on the operating system's underlying window manager (on Mac and Windows they're always capable, but on Linux there are tons of different window managers/compositors, and NOT all support transparent windows, etc). It says that in case transparency is not supported, the alpha property will stay at 1.0 if you try to read it again later. However the page also notes that on Linux (X11), the attributes are updated asynchronously which means that you can't trust the value you read (if you change alpha and then immediately try to read it, you'll still read the old value, so you can't use that method to check if alpha was successfully changed on Linux).
As for the other answers saying that you first need to use root.wait_visibility(root) on Linux to make sure the window is visible on screen before setting the alpha attribute... I don't know, since I don't have a Linux machine to check. But I heavily doubt that it's needed anymore, since the official manual says that alpha is supported and says nothing about that command being necessary. Either way, it doesn't hurt to add the wait_visibility trick too... It is simply a command that runs a very brief event loop that waits until the actual window has appeared on the user's screen. So it's probably still a good idea to add that command before all of your attribute-setting. Especially since it's proven to help the alpha work on Linux on old TCL/TK versions! PS: You don't need the (root) argument, and should type root.wait_visibility() instead, which means "wait for self (root in this case since we called the command on the root object)".
Update:
Daniel in the comments below has let me know that root.wait_visibility() is still necessary on Ubuntu 19.10. Although he didn't specify his Python, TCL/TK or TkInter versions so maybe they're outdated on his system. Either way, sounds like it's a safer bet to always include that command for backwards compatibility!

Related

Changing height of status bar in wxpython on mac?

I'm writing an app in python using the wxPython gui library for the mac, and finding that you can't change the height of a window status bar, even though there is a function setMinHeight() function in the wxPython library.
According to this reference, setMinHeight isn't implemented for OSX. Is there a workaround that might allow for changing the height of the status bar?
From playing around with StatusBar on OSX, it seems like changing the status bar height using the built-in class is impossible. I also tried the highly customizable EnhancedStatusBar class, but despite all its effort, the size remains unchanged because it still relies on the SetMinHeight method of the wxPython StatusBar.
The only hope that I can see (and from a few minutes of playing around it doesn't seem too difficult) is to create a custom "StatusBar-like" object. On OSX, this shouldn't be more than a horizontal line and some text at the bottom of your window. If you're planning to make the program cross-platform, you can do some OS detection to determine whether or not to use the built-in StatusBar class or your custom one.
I hope this helps.

Python Tkinter: Adding widgets to file dialogs

I am using Tkinter with Python 2.6 and 2.7 for programming graphic user interfaces.
These User Interfaces contain dialogs for opening files and saving data from the tkFileDialog module. I would like to adapt the dialogs and add some further entry widgets e.g. for letting the user leave comments.
Is there any way for doing so?
It seems that the file dialogs are taken directly from the operating system. In Tkinter they are derived from the Dialog class in the tkCommonDialog module and call the tk.call("tk_getSaveFile") method of a frame widget (in this case for saving data).
I could not find out where this method is defined.
call method is defined in _tkinter.c, but there is nothing interesting for your particular task there. It just calls a Tcl command, and the command tk_getSaveFile does all the work.
And yes, when there is a native file dialog on the operating system, tk_getSaveFile uses them (e.g. GetSaveFileName is used on Windows). It could be possible to add widgets there, but not without tampering with C sources of Tk. If you're sure that your target uses non-native Tk dialogs, you could add something to its widget hierarchy by hacking ::tk::dialog::file:: procedure from Tk (see library/tkfbox.tcl).
I would rather take an alternative implementation of tk_getSaveFile, written in pure Tcl/Tk and never using the OS facility. This way, we can be sure that its layout is the same for all OSes, and it won't suddenly change with a new version of Tk. It's still far from trivial to provide a convenient API for python around it, but at least, it is possible.
I had to get rid of the canvasx/y statements. That line now simply reads set item [$data(canvas) find closest $x $y], which works well. $data(canvas) canvasx $x for its own works well but not in connection with find closest, neither if it is written in two lines.

Python, transparent window with a red outine of a rectangle

Hi I am new to this whole coding thing I was suggested to use Python. The version I have now is 2.7. I need help with making a transparent window to the copacity of 100 so that you can actually see through it and I also want to know how to make a fairy thick, out line of a rectangle in the colour red.
Help me please :S Thanks!
Unfortunatelly, there is not such an easy thing as sa "trasnparent window" - althougmodern widnow managaers do have various opacity controls for the windows, those just affect the windows as a whole - and do not integrate at all with the program running "inside" the windows. There may even be, for some of them, a way to call functions to explicitly set up the opacity level of a given window, but I don't think it willbe possible for all of them.
That said, it is possible to get grab of the "root" window and draw directly on the screen - -bypassing the window manager. There are APIs for that at least on Windows and Linux (you have to mention in what operating system you need that working) - but it will amount to not a trivial research work, since this is not what is expected of a "well behaved app" - for which the GUI toolkits are written and documented. You will need to write xlib code in Linux, and directly call win32 api's on windows - both are possible from Python - as possible as under-documented.
And once you get to draw the rectangle, since you are bypassing the window manager, you willhave to care about every low-level detail of your app: mouse event handling, screen-redrawing (and notifying the system of drawing taking effect over other windows), and so on.

How do I get a list of all windows on my gnome2 desktop using pygtk?

I'm a bit confused with some gtk and gnome concepts. I'm trying to get list of non minimized windows on my gnome2 desktop, but after reading the pygtk documentation and inspecting the results, I can't understand the results.
Neither of the two snippets below appears to work.
First I tried this..
>>> gtk.gdk.window_get_toplevels()
[<gtk.gdk.Window object at 0xb74339b4 (GdkWindow at 0x8a4c170)>]
>>> gtk.gdk.window_get_toplevels()[0].get_children()
[]
then this
>>> d = gtk.gdk.DisplayManager()
>>> d.get_default_display().get_screen(0).get_root_window().get_children()
[<gtk.gdk.Window object at 0x89dcc84 (GdkWindow at 0x8a4c170)>, <gtk.gdk.Window object at 0x89dccac (GdkWindow at 0x8a4c0c0)>]
As seen in the console output, the second option returns two windows. But I haven't been able to figure out what they are. None of them has any children and I allways get those two windows regardless how many windows I have on my desktop.
Could anybody explain the hierarchy of objects of the typical gtk based desktop environment?
I can't understand why the above code doesn't work.
Please refrain from posting alternative solutions that resource to wnck, xlib, qt, etc. I'm more interested in understanding what I am doing wrong than in getting advice such us checking other libraries.
Your constraint is like saying "I want to build a CD player using only a banana. Please refrain from posting alternative solutions that resort to lasers." GTK can't do that, you're using the wrong tool for the job.
Here's an explanation of what a "window" actually means and why your code doesn't work:
First off, you need to understand the difference between a gtk.Window and a gtk.gdk.Window. A GTK window is a top level GTK widget that can contain other widgets. It is usually linked to a window on your desktop, but doesn't have to be - in GTK 3 there is an OffscreenWindow.
A GDK window, on the other hand, is platform-dependent. On an X desktop it is a thin wrapper around an X window, which is not necessarily a toplevel desktop window. On other systems it exists to abstract away the windowing system. A GDK window receives events, so some GTK non-window widgets have their own GDK windows. "Window" is really a terrible name for these objects, but it was inherited from X and it's probably not going to change.
Each GTK process only knows about its own windows. You can get a list of the toplevel GTK windows of your own application using gtk.window_list_toplevels(). Getting the children of these windows should return you the GTK widgets that they contain. However, you can't descend into the widget hierarchy of other processes' windows. For example, what if another process has a window with a child widget that is a custom widget that your process doesn't know about? What should it report as the type of that widget?
Getting a list of the toplevel GDK windows with gtk.gdk.window_get_toplevels() is basically the same as getting a list of the toplevel X windows, as far as I understand it. You have no way of knowing what kind of windows they are - they might be the Gnome Panel, or they might be Qt windows, or they might be something else altogether that doesn't correspond with a desktop window.
Libwnck (link to the overview of what it does) can get you a list of non-minimized windows, and their titles, but it won't allow you to see inside them. There's no way to do that. Libwnck uses GDK internally, so technically you could do it using GDK, but why would you bother if there's already a library that does that for you? If you really want to do it yourself, look at the libwnck source code.
The windows you get are the windows that were created within your process. To get the list of windows, you need to query the properties of the root window, like this:
import gtk.gdk
root = gtk.gdk.get_default_root_window()
for id in root.property_get('_NET_CLIENT_LIST')[2]:
w = gtk.gdk.window_foreign_new(id)
if w:
print(w.property_get('WM_NAME')[2])
Please note that GDK is a thin layer over underlying OS graphics engine (X11/Quartz/Aqua/GDI etc) and result may differ on different NIX devices.

Get active gtk window in python

How would I get a handle to the active gtk.Window in python? (not a window I created, but the currently focused window).
The answer is actually not OS-specific -- you can do it within GTK. You can get a list of all the toplevel windows from the application using gtk.window_list_toplevels(), then iterate through it until you find one where window.is_active() returns True.
If you want to consider other windows than the ones from your application, then you could try gtk.gdk.screen_get_default().get_toplevel_windows() but this will only get you GDK windows and not GTK windows, because you have no way of knowing whether those GDK windows are actually associated with GTK windows.
[Note: This answers the question as the OP originally phrased it, which other readers will probably be searching for - not the very different question that they changed it to in comments on the other answer.]
If you have a GtkApplication and have added your GtkWindows to it - which you should probably do, because GtkApplication can do lots of really cool stuff! - then you can use GtkApplication's much simpler API dedicated to this purpose:
Gtk.Application.get_active_window():
Gets the “active” window for the application.
The active window is the one that was most recently focused (within the application). This window may not have the focus at the moment if another application has it — this is just the most recently-focused window within this application.

Categories

Resources