for my program I need to place an transparent image on top of multiple frames (as a kind of overlay), and apparently, placing the image in a canvas is a good way to do it as they support transparency. However, the canvas has a non-transparent border around it, which means it just sits on top of the frames with a a gray rectangular background around it, and I have no clue how to fix it:
from tkinter import *
root = Tk()
root.title("Transparency")
root.geometry("500x500")
frame = Frame(root, width=500, height=500, bg="yellow")
frame.place(x=0, y=0)
photoimage = PhotoImage(file="example1.png")
canvas = Canvas(frame, width=300, height=200, bg="red")
canvas.create_image(128, 64, image=photoimage)
canvas.place(x=100, y=100)
root.mainloop()
This is not my actual program, but it does replicates what happens. I also need to use the Place manager instead of the others (my program uses a lot of coordinates to place several widgets).
This is what it looks like when running the above code
This is what I want it to look like (assume the yellow underneath the image are a bunch of frames).
All I am trying to do is place a transparent Canvas on top of opaque Frames, and it should be impossible to tell that the Canvas is even present.
How do I accomplish this?
Related
I'm trying to create a window with the same dimensions as the window that mac os open when I click on a video, the video resolution is 1080x1920 or 9:16 aspect ratio, this is how it looks:
Want to create a window from tkinter same as that, im using window config 1080x1920, but doesnt look nothing like that, looks horizontal
Ss there a way I can make the window same as the one that mac open? Want to show like a preview how it would looks like when its done, so need the same dimensions.
self.background = tk.PhotoImage(file="./assets/test.png");
# background image
self.canvas = tk.Canvas(self, width=1080, height=1920, bg="white");
self.canvas.pack(fill="both", expand=True);
self.canvas.create_image(0, 0, image=self.background, anchor="nw");
This is the code for the canvas background.
My code is the following:
import tkinter as tk
#setting up window.
root = tk.Tk()
root.title("CSV Maker")
root.geometry("600x300")
#setting up frames.
leftFrame = tk.Frame(root, bg="red", width=300, height=300)
rightFrame = tk.Frame(root, bg="blue", width=300, height=300)
#placing frames on window.
leftFrame.grid(row=0, column=0)
rightFrame.grid(row=0, column=1)
#setting up labels.
inputPathLabel = tk.Label(leftFrame, text="Input File Path:")
#placing labels on frames.
inputPathLabel.grid(row=0, column=0)
root.mainloop()
When I remove the label I get the following:
Without label
However when I leave the code as it is below (with a label), I get a completely different result. It seems as if the frame was resized to another size than the one that I selected and the color is gone. Why is this?
With label
That is simply how tkinter was designed to work. When you use pack or grid, frames (or any other widget) will shrink or expand to try to fit all of its contents.
99.9% of the time, this is the behavior you want. Tkinter is really good at making GUIs the appropriate size.
From the official documentation for grid:
The grid geometry manager normally computes how large a master must be to just exactly meet the needs of its slaves, and it sets the requested width and height of the master to these dimensions. This causes geometry information to propagate up through a window hierarchy to a top-level window so that the entire sub-tree sizes itself to fit the needs of the leaf windows. However, the grid propagate command may be used to turn off propagation for one or more masters. If propagation is disabled then grid will not set the requested width and height of the master window. This may be useful if, for example, you wish for a master window to have a fixed size that you specify.
From the documentation for pack:
The packer normally computes how large a master must be to just exactly meet the needs of its slaves, and it sets the requested width and height of the master to these dimensions. This causes geometry information to propagate up through a window hierarchy to a top-level window so that the entire sub-tree sizes itself to fit the needs of the leaf windows. However, the pack propagate command may be used to turn off propagation for one or more masters. If propagation is disabled then the packer will not set the requested width and height of the packer. This may be useful if, for example, you wish for a master window to have a fixed size that you specify.
Notice that place doesn't have the same behavior. From the place documentation:
Unlike many other geometry managers (such as the packer) the placer does not make any attempt to manipulate the geometry of the master windows or the parents of slave windows (i.e. it does not set their requested sizes). To control the sizes of these windows, make them windows like frames and canvases that provide configuration options for this purpose.
I have created a Window using tkinter and configured the root to have a bg colour. I set bg="Black" to have the whole Window Black, but when I tested the script, the space around the Window was Black but the middle of the Window was still White.
I tried searching the internet, but I could not find anything (it may be the phrasing but I don't know a better way to phrase this). I tried different ways to phrase this question like "Why does the background colour of a Window not fill the middle?" and "Why does the bg="Black" not fill the middle in Python", but it comes up with tutorials for tkinter and picture colouring in Python.
I also tried attaching other attributes to the config but like fg="Black" but the code throws a Syntax Error stating "_tkinter.TclError: unknown option "-fg" ". I don't know what is causing this or how to fix it.
Here is the segment of the code:
def mainloop_sw():
root = tk.Tk()
root.title("Adventure")
root.geometry("250x250")
root.config(bg="Black")
app = Window(root)
app.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
root.mainloop()
if __name__ == "__main__":
mainloop_sw()
As you can see the root is configured to have the bg="Black" but the middle section is left white.
Here is a picture for context:
Image of Window
As you can see the middle is not coloured in black, and yes, there are widgets, but all of them are coloured in black (for labels) or grey (for buttons) there are no other widgets in the program which could cover up the background. If you need a confirmation of this you can just ask for the full code.
Why is the middle bit of the Window (shown in the image above) not coloured in Black when the root is configured to have bg="Black" and how do I fix it?
The only explanation is that Window is a Frame or some other widget with a background that is white.
The solution is to modify Window to have a background that matches the background of the root window.
I'm creating an instrument panel in Tkinter (Python 3.7) and have been attempting to place an image on top of other widgets to augment their appearance. The problem is, every time I place an image it ends up in the background. Ideally I would like to put an image with transparency over all the widgets in my panel, but I would settle for simply being able to put non-transparent images over parts of my display.
I've been using place() to position my widgets since I never want the widgets to move and only need it to work for a specific screen resolution.
So far I've tried using the PIL package and tried placing the image inside a label and a canvas, but both seem to have the same result. Even if I place my widgets inside the canvas with the image, the widgets will show up in front.
Here's a simple example:
import tkinter as tk
import PIL.Image
import PIL.ImageTk
root = tk.Tk()
image = PIL.Image.open('esis/decals_green.gif')
photo = PIL.ImageTk.PhotoImage(image)
label = tk.Label(root, image=photo)
label.image = photo #keep reference
sampleWidget = tk.Button(root, text='Test')
sampleWidget.place(x=0, y=0, height=100, width=100)
label.place(x=0, y=0, height=200, width=200)
root.mainloop()
Even though I'm placing the image label last, it shows up underneath the button.
When tkinter widgets overlap, tkinter will use the stacking order (sometimes referred to as a z-index) to determine which widget overlays the other.
The stacking order defaults to the order in which the widgets are created (widgets created earlier are lower in the order than widgets created later). You can change this ordering with the lower and lift methods. Because you created the button widget last, it will have a higher place in the stacking order and thus it will appear on top of the image.
If you wait to create the label with the image until after all of the other widgets have been created, it will be highest in the stacking order and thus appear on top of all other widgets. You could also leave the code as-is and add label.lift() near the end of the code to raise it to the top of the stacking order.
This is the code that's giving me trouble.
f = Frame(root, width=1000, bg="blue")
f.pack(fill=X, expand=True)
l = Label(f, text="hi", width=10, bg="red", fg="white")
l.pack()
If I comment out the lines with the Label, the Frame displays with the right width. However, adding the Label seems to shrink the Frame down to the Label's size. Is there a way to prevent that from happening?
By default, both pack and grid shrink or grow a widget to fit its contents, which is what you want 99.9% of the time. The term that describes this feature is geometry propagation. There is a command to turn geometry propagation on or off when using pack (pack_propagate) and grid (grid_propagate).
Since you are using pack the syntax would be:
f.pack_propagate(0)
or maybe root.pack_propagate(0), depending on which widgets you actually want to affect. However, because you haven't given the frame height, its default height is one pixel so you still may not see the interior widgets. To get the full effect of what you want, you need to give the containing frame both a width and a height.
That being said, the vast majority of the time you should let Tkinter compute the size. When you turn geometry propagation off your GUI won't respond well to changes in resolution, changes in fonts, etc. Tkinter's geometry managers (pack, place and grid) are remarkably powerful. You should learn to take advantage of that power by using the right tool for the job.