Desktop Goose like program - python

i have been trying to create a python program similar to desktop goose in the aspect of a widget moving freely around the screen.
First i tried to create a window with tkinter and make a transparent window
with a PNG picture of a character and then moving the window with win32gui or any other library that would allow me to do this.
But first, the tkinter transparent window thing doesn't work because the widgets inherit the transparency, so there is no way i can display the PNG.
Then i had trouble finding any win32gui function that would allow me to move the windows, i just found stuff that would let me resize them.
Is there any way i can do any of these two tasks?

You can create a transparent window using a transparent PNG image as below:
import tkinter as tk
# select a color as the transparent color
TRNAS_COLOR = '#abcdef'
root = tk.Tk()
root.overrideredirect(1)
root.attributes('-transparentcolor', TRNAS_COLOR)
image = tk.PhotoImage(file='/path/to/image.png')
tk.Label(root, image=image, bg=TRNAS_COLOR).pack()
# support dragging window
def start_drag(event):
global dx, dy
dx, dy = event.x, event.y
def drag_window(event):
root.geometry(f'+{event.x_root-dx}+{event.y_root-dy}')
root.bind('<Button-1>', start_drag)
root.bind('<B1-Motion>', drag_window)
root.mainloop()
Then you can use root.geometry(...) to move the root window.

Related

Tkinter Transparent Background macOS

I've been messing around with different code snippets and combinations for a while now, trying to make it so my .gif file would have a transparent background. I've been successful in making the actual background transparent, but I find that my .gif goes transparent with it:
import tkinter as tk
root = tk.Tk()
root.overrideredirect(1)
root.wm_attributes("-topmost", True)
root.wm_attributes("-transparent", True)
root.config(bg='systemTransparent')
root.geometry("+300+300")
root.image = tk.PhotoImage(file="sample.gif")
label = tk.Label(root, image=root.image)
label.config(bg='systemTransparent')
label.pack()
root.mainloop()
I have found that whenever I use both root.config(bg='systemTransparent') and label.config(bg='systemTransparent'), the entire window and gif go transparent, but when I use just one or neither, I am left with a light-gray background.

In Tkinter's canvas is it possible to have mouse events ignore transparent parts of an image?

I've got an image (drawn in Pillow) with a transparent background. I can add this onto a Tkinter canvas via create_image() and bind mouse events to it, e.g. button clicks.
However, Tkinter canvas triggers the mouse events for the entire image including the transparent background.
Is there any way in Tkinter to have mouse events ignore an image's transparent pixels?
Everything else works fine and as expected, however I've not been able to find any option or if it's even possible to have Tkinter ignore mouse events for transparency in images?
Thanks in advance to anyone who knows!
EDIT2: On request, more details. The situation is that I've got a map which serves as the background of the canvas object, on this map I draw routes, and I want those routes to react to mouse events such as clicks.
for route in travel_routes:
route_map = route.draw_route_map(canvas_width, canvas_height)
self.CanvasTravelMapRoutes.append(ImageTk.PhotoImage(route_map))
self.CanvasTravelMap.create_image(
0, 0, image = self.CanvasTravelMapRoutes[-1], anchor = tk.NW, tag = (route.RouteID, 'travel_route') )
self.CanvasTravelMap.tag_bind('travel_route', "<Button-1>", self.travel_canvas_route_click)
In the route class, the draw_route_map method works as follows:
route_map = Image.new("RGBA", (canvas_width, canvas_height), (0, 0, 0, 0))
draw = ImageDraw.Draw(route_map)
draw.line()
draw.ellipse()
etc. etc.
The result is a route_map image laid on top of the canvas, but which is mostly transparent except for the lines and circles drawn to mark the route's course across the map.
All elements of this code function as designed, except that the canvas mouse events also respond to the transparent parts of the route_map images. Obviously, this means any click anywhere on the canvas always selects whichever route_map is on top and not the specific line/mark being clicked on.
So if you wanted to have this kind of collision you could try this:
from tkinter import Tk, Canvas
from PIL import Image, ImageTk
import requests
url = 'http://media-s3-us-east-1.ceros.com/g3-communications/images/2019/01/15/05eea4b9b9ce010d2dd6b0c063d2f5ca/p1-blob.png?imageOpt=1&fit=bounds&width=893'
data = requests.get(url, stream=True).raw
image = Image.open(data)
def on_opaque(event, offset, img):
print('clicked on bounding box')
x, y = event.x - offset[0], event.y - offset[1]
if img.getpixel((x, y)) != 0:
print('clicked on opaque pixel')
root = Tk()
photo = ImageTk.PhotoImage(image)
canvas = Canvas(root, height=image.height, width=image.width, highlightthickness=0)
canvas.pack(fill='both', expand=True)
offset_x, offset_y = 0, 0
c_img = canvas.create_image(offset_x, offset_y, image=photo, anchor='nw')
canvas.tag_bind(c_img, '<Button-1>', lambda e: on_opaque(e, (offset_x, offset_y), image))
root.mainloop()
I use image from internet, you can use your own, it is just that you can test it immediately. Basically it binds the whole image to button click, but then in the callback it additionally checks if the click was in a position where there is not a transparent background, also be careful with fake transparent background, I then suggest that you set the background of canvas to black and see if the bg behind image is black too.

Tkinter: Is there any way to remove the top bar of my program?

Okay, so i am using tkinter to make a GUI, i feel like the top bar looks kinda ugly so that's why i was planning to remove it and put some nice icons. I used this line of code to remove the top bar gui.overrideredirect(True) and it worked :D, but you can't move the program around the screen (it sticks to the top-left corner of the screen). Is there any other way i can do this without sticking my program to the corner? Thanks.
import requests
import tkinter as tk
#GUI Config
gui = tk.Tk()
gui.geometry('970x569')
gui.title("Zombs Royale Tools v1")
gui.resizable(False, False)
#Code below is the one i used to do this[![enter image description here][1]][1]
gui.overrideredirect(True)
#Background-image
bgImage = tk.PhotoImage(file="width.png")
background_label = tk.Label(gui, image = bgImage)
background_label.place(x=0,y=0,relwidth=1, relheight=1)
#GUI Widgets#
#Exit Button
exit_image = tk.PhotoImage(file="close.gif")
exit_button = tk.Button(gui, image=exit_image, borderwidth=0, command=gui.destroy)
exit_button.place(rely=0.01, relx=0.01)
Removing the titlebar is done with override redirect. However, this removes every window function as well. That includes moving the window around and resizing it.
This means with overrideredirect you can skip the
gui.resizable(False, False)
One thing you can do is provide more info for the window’s geometry:
gui.geometry('970x569+600+500')
The 2 last numbers provide the info regarding the positioning of your window on the desktop, in case you don’t want it to be spawned on the top left corner.
If you want to make the window movable you will have to integrate your own code. It has been discussed here before.
Eg.
here

Tkinter: Display an image on top of other [duplicate]

I am making a chess program and I want to be able to drag the pieces. In order to do this, I put the image of the piece on a Canvas so it can be dragged (I can also use a Label if I want). However, when I drag the piece there is a white square that surrounds the image of the piece.
When I researched the problem, many people gave this solution:
drag_canvas = Canvas(self, height=80, width=80, bg="yellow")
root.wm_attributes("-transparentcolor", "yellow")
This caused the background to be transparent but it was not the chessboard that was visible, it was the program behind the GUI
.
Is there any way I can have the background be transparent and show the chessboard behind rather than the program behind the tkinter window?
Note: I do not mind using any other widget (e.g. a Label) but they must use modules that come default with Python (so no PIL) as this program needs to be used in an environment where I cannot download other modules.
Question: How to make a tkinter canvas background transparent?
The only possible config(... option, to set the background to nothing
c.config(bg='')
results with: _tkinter.TclError: unknown color name ""
To get this result:
you have to hold the chess board and figures within the same .Canvas(....
self.canvas = Canvas(self, width=500, height=200, bd=0, highlightthickness=0)
self.canvas.create_rectangle(245,50,345,150, fill='white')
self.image = tk.PhotoImage(file='chess.png')
self.image_id = self.canvas.create_image(50,50, image=self.image)
self.canvas.move(self.image_id, 245, 100)
Tested with Python: 3.5 - TkVersion: 8.6
A windows only solution is to use the pywin32 module that can be installed with:
pip install pywin32
With pywin32 you can alter the window exstyle and set the canvas to a layered window. A layered window can have a transparent colorkey and is done in the example below:
import tkinter as tk
import win32gui
import win32con
import win32api
root = tk.Tk()
root.configure(bg='yellow')
canvas = tk.Canvas(root,bg='#000000')#full black
hwnd = canvas.winfo_id()
colorkey = win32api.RGB(0,0,0) #full black in COLORREF structure
wnd_exstyle = win32gui.GetWindowLong(hwnd, win32con.GWL_EXSTYLE)
new_exstyle = wnd_exstyle | win32con.WS_EX_LAYERED
win32gui.SetWindowLong(hwnd,win32con.GWL_EXSTYLE,new_exstyle)
win32gui.SetLayeredWindowAttributes(hwnd,colorkey,255,win32con.LWA_COLORKEY)
canvas.create_rectangle(50,50,100,100,fill='blue')
canvas.pack()
Explaination:
First we need the handle of the window which is called hwnd and we can get it in tkinter by .winfo_id().
Next we get the actual extended window style by GetWindowLong and ask specific for extended style information with win32con.GWL_EXSTYLE.
After that we do a bitwise operation in hexadezimal to alter the style with wnd_exstyle | win32con.WS_EX_LAYERED the result is our new_style.
Now we can set the extended style to the window with SetWindowLong. Finally we have our LayeredWindow which has additional Attributes we can work with. A transparent ColorKey can be set with SetLayeredWindowAttributes while we just use LWA_COLORKEY the alpha parameter has no use to us.
Important note: After defining a transparent colorkey, everything in that canvas with that color will be transparent.

How do I stop flickering in my transparent Splash screen in Tkinter?

Using a bit of modified code I found on the web for creating a generic Tkinter splash screen, I tried to to create a transparent splash screen kind of thing with a .png. I know this code will only work with Windows and I am fine with that.
However, I notice there is flickering (Canvas area is black before it draws the picture) with the image when it draws on the screen. I don't know very much about it but I suspect it has to do something with the buffering of the image after googling and reading. I also read that canvas supports double buffering so the flickering shouldn't be happening so maybe it's the Top Level widget or something.
In any case is there any fix to this? I'd really like to continue using Tkinter for this and it would be a huge letdown not to be able to get rid of the flickering. Here is the code I am using below.
from Tkinter import *
import ttk
from PIL import Image, ImageTk
import time
class Splash:
def __init__(self, root, filename, wait):
self.__root = root
#To use .pngs or .jpgs instead of just .bmps and .gifs, PIL is needed
self.__file = ImageTk.PhotoImage(Image.open(filename))
self.__wait = wait + time.clock()
def __enter__(self):
# Hide the root while it is built.
self.__root.withdraw()
# Create components of splash screen.
window = Toplevel(self.__root)
#Set splash window bg to transparent
window.attributes('-transparent', '#FFFFFE')
#Set canvas bg to transparent
canvas = Canvas(window,bg="#FFFFFE")
splash = self.__file
# Get the screen's width and height.
scrW = window.winfo_screenwidth()
scrH = window.winfo_screenheight()
# Get the images's width and height.
imgW = splash.width()
imgH = splash.height()
# Compute positioning for splash screen.
Xpos = (scrW - imgW) // 2
Ypos = (scrH - imgH) // 2
# Configure the window showing the logo.
window.overrideredirect(True)
window.geometry('+{}+{}'.format(Xpos, Ypos))
# Setup canvas on which image is drawn.
canvas.configure(width=imgW, height=imgH, highlightthickness=0)
canvas.pack()
# Show the splash screen on the monitor.
canvas.create_image(imgW // 2, imgH // 2, image=splash)
window.update()
# Save the variables for later cleanup.
self.__window = window
self.__canvas = canvas
self.__splash = splash
def __exit__(self, exc_type, exc_val, exc_tb):
# Ensure that required time has passed.
now = time.clock()
if now < self.__wait:
time.sleep(self.__wait - now)
# Free used resources in reverse order.
del self.__splash
self.__canvas.destroy()
self.__window.destroy()
# Give control back to the root program.
self.__root.update_idletasks()
self.__root.deiconify()
if __name__ == '__main__':
#thread2 = myLazyDoStuffThread()
root = Tk()
with Splash(root,'splash.png',3):
myprog = ApplyGUIAndOtherThings(root)#,thread2)
root.mainloop()
A rule of thumb you should follow is to never put a call to sleep in a GUI. It does exactly what it says, it causes your whole application to sleep. This means that the GUI is not able to redraw itself, and is likely the cause of your flicker.
If you want a window to be destroyed after a period of time, use the after method. For example:
delta = (self.__wait - now) * 1000
self.after(delta, self.close)
You'll need to define self.close to destroy the window.
This gives you an opportunity to add a little "fade away" effect if you like. You do this by checking to see if the alpha of the splash screen is below some threshold (say, 10%) and destroy it. If it's not, reduce the alpha by 10% and call the function again in 100 ms.

Categories