Can't set frame background image without frame resizing to fit image - python

I can set the background of the main window, and I don't need to worry about the window trying to fit the background image or the image shoving the widgets out of the way.
However when I try to do the same with a frame it becomes a huge mess...
I have tried a few things but everything seams to be related to resizing the image itself and I don't want to warp the image. I want the image to be in the frame and NOT have the frame resize to fit the image.
Is there a way to place the image into the background of the frame without the frame changing in size?
EDIT: Note: The image I am using is large enough to fill the screen so if there is resizing going on by the user the image will cover all the extra space.
So this is how I add a background image to the main window:
bgImage=PhotoImage(file="./Colors/bgImage.png")
bgLable = Label(root,image = bgImage)
bgLable.image = bgImage
bgLable.grid(row=0,column=0,columnspan=3,rowspan=8)
However when I try to do the same thing with a frame it resizes the frame as well:
FrameTL = Frame(root, width = 100)
FrameTL.grid(row = 0, column = 0, rowspan = 20, columnspan = 1, sticky = W+N+S)
TLbg = Label(FrameTL,image = bgImage)
TLbg.image = bgImage
TLbg.grid(row=0,column=0)
There were some other things I tried but they would warp the image to fit the window/frame and I do not want to warp the image.
EDIT:
I have found a work around of sorts. Instead of using frames I used .grid for all my widgets except for the widgets I needed to be on my side menu. The side menu widgets were not aliening to the top left of the window so I was trying to use frames to fix the problem (using .place for now). The frames would work but I could not find a way to make frames transparent so I can keep my background from my root window. And that is why I got stuck on trying to a background image to my frame but without the frame resizing to fit the image.

Is there a way to place the image into the background of the frame without the frame changing in size?
Yes. Use place with relative coordinates. The following will place the label with your image in the center of the root window, and will not affect any other widgets.
some_frame = tk.Frame(root, borderwidth=2, relief="raised", width=200, height=200)
...
background = tk.Label(some_frame, text="I am in the center", background="pink")
background.place(relx=.5, rely=.5, anchor="c")
This is one of the few times when I think place is superior to using grid or pack. This is what the official documentation says about place:
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.

Related

how to set window size with frame? [duplicate]

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.

Disappearing tkinter images when label is placed

I am currently making a GUI application using Python an TkInter and I have problem with images "randomly" disappearing. I am aware that you need to keep references to your images to prevent them from being garbage collected, and I don't believe this is what causes my problems.
What I currently have are TkInter labels with images on them. The issues arise when I either move my window between screens (I have two monitors) or sometimes when I add new labels to the canvas. What happens is that a select few (not all) images disappear, but they will reappear if I re-size my window. What I have tried is to issue a redraw by calling the update() method on the root tk element but this does not solve my issues. Is this a known issue in TkInter?
Edit:
Here is the specific piece of code that makes the images disappear:
def showNoMatch():
global tkImageNoMatch, noMatchLabel, panel
img = Image.open("noMatches.png")
tkImageNoMatch = ImageTk.PhotoImage(img)
noMatchLabel = Label(panel, image = tkImageNoMatch, borderwidth = 0)
noMatchLabel.place(x = 250, y = 550)
Which has the following effects on my gui:
Before adding the noMatchLabel:
And after adding the noMatchLabel:
Notice that the two buttons on the sides disappear, yet they reappear when I re-size the window.

How to size a Tkinter Checkbutton by pixels when there's no text but also no image?

A Tkinter Checkbutton widget can have a text or an image/bitmap. When using text the width and height configurations of the widget refer to characters, rather than pixels, but when using an image/bitmap they refer to pixels. I'm using a Checkbutton widget with no image nor text - just a plain checkbox. Is there a simple way to have it sized in pixels?
Note: I am familiar with the hack of wrapping it in a Frame, but am hoping this is avoidable here, as the widget itself does support by-pixel sizing.
If there's no simple way of instructing the widget to use "image mode" in these circumstances, what's a simple way of feeding it an empty bitmap (if that would at all work)?
In case it matters: I'm using Python 3.4.3 on Ubuntu 15.04.
Give it a 1x1 image (one pixel wide, one pixel tall). That will cause the size attribute to be based on pixels, and the image you give it will be virtually invisible.
import tkinter as tk
...
img = tk.PhotoImage(width=1, height=1)
cb = tk.Checkbutton(root, width=40, height=40)
...

python tkinter canvas 'transparent'

I think transparent is the right word I'm looking for. Hopefully my description will explain it properly no matter what.
I have a graph of time based data going back decades. Pretty much simply setup to show one day per x-pixel, unless zoomed in closer. I would like to have a box, maybe along the lines of 5x100, appear on top of the graph so when I move the mouse over the graph the box will move and keep pace with the mouse. Anotherwords showing what was happening in the 5 furthest days 'x number of days prior'. Anotherwords when computing an average going forward what are the next values to be falling off as new data arrives. Naturally I want the underlying graphed data to be displayed with the transparent box on top of it outlining the days in question. This may get crazy enough to be a much wider box with two areas that are colored light grey or something like that to show the areas in question but the colored areas are separated by numerous days(could be multiple transparent windows that are tracked together as well. Is this feasible with tkinter? From the research I've been doing it's questionable if using
root.attributes('alpha', .30)
would work or not. It doesn't sound like I could do something like as it would end up making the graph transparent to whatever is underneath it.
self.Graph.create_line()
self.Box.attributes('alpha', .30)
If I understand correctly I have to use
attributes
right at the root level versus the individual 'window' level so the above (severely chopped down) code wouldn't work...or would it. I haven't had a chance to try anything out yet to see what happens...that will be later on this evening. Kinda hoping to save myself a little time by asking now and you never know who else may need the help sometime.
If I understand what you're trying to do, it's going to be pretty hard.
Setting window attributes works just fine to make a window transparent. You've got a minor problem in the code—attributes start with a hyphen—but otherwise you've got it right:
self.Box.attributes("-alpha", .30)
However, it sounds like you want that Box to be an embedded part of the graph window, not its own top-level window that can be dragged around by the user, etc. Unfortunately, Tkinter does not have any notion of child windows, and it doesn't expose nearly enough of the native stuff you'd need to fake them by creating an immobile window and manually moving it to track the movements of another window. So, you don't have a window, which means you don't have window transparency.
The obvious thing for Box to be is some kind of widget, like a Frame or Canvas. But widgets don't have transparency.
Box could instead be just a collection of elements drawn onto the same Canvas as the Graph. That seems promising… but none of the Canvas methods handle alpha transparency. (Some of them do handle all-or-nothing transparency, but that doesn't help.)
One thing that does handle transparency is PhotoImage. So, if you draw Box off-screen, get the resulting contents as a PhotoImage, add the alpha (e.g., via PIL), then create_image the result… close, but no cigar. Depending on the settings of the underlying Tk library, Tkinter may just draw the pixmap with 1-bit transparency or ignore transparency completely. (Experiment with loading alpha-transparent PNG files in PIL and drawing them on a Canvas.) So, unless you want an app that looks right on some systems, doesn't draw the Box at all on others, and draws it opaque on others, this is a dead end.
So, what's left? Only manual compositing: Draw the Graph and the Box on separate off-screen windows, get the pixmaps, use PIL to compose them, and create_image the result.
At which point you're probably better off just using something like PIL's ImageDraw or a more powerful library to construct the pixmap in the first place. Or, of course, using a more powerful GUI library than Tk, like Qt or wx.
Maybe this can give you some ideas to play with:
from tkinter import *
root = Tk()
c = Canvas(root, width=640, height=480, bd=0, highlightthickness=0)
c.create_line(0,240,640,240, fill='blue')
c.pack()
#pil image with transparency
try:
from PIL import Image, ImageTk
except ImportError:
pass
else:
pim = Image.new('RGBA', (5,100), (0,255,0,64))
photo = ImageTk.PhotoImage(pim)
c.create_image(200,200, image=photo, anchor='nw')
#blank standard photoimage with red vertical borders
im = PhotoImage(width=7, height=480)
dat = ('red',)*480
im.put(dat, to=(0,0))
im.put(dat, to=(6,0))
box = c.create_image(0, 0, image=im, anchor='nw')
def on_motion(event):
left,top = c.coords(box)
dx = event.x - (left+7)
c.move(box, dx, 0)
c.bind('<Motion>', on_motion)
root.mainloop()

Resize Tkinter listbox when window resizes with Grid

I'm working on a Tkinter application using the Grid geometry manager (It's my first time using Grid, and I love it! :D) that contains a scrolling listbox that displays options whenever a user selects an option.
It's working well, but the window is small and ugly. When I maximize it, everything else resizes fine (thanks to columnconfigure) but the listbox stays the same height. Is there a simple way to fix this?
(I have seen this question but it's for Pack, not Grid)
Thanks in advance.
Code sample because one was asked for:
self.tasklist = Listbox(self.frame, exportselection=0)
self.tasklist.grid(row=1, sticky=W+E+N+S)
yscroll = Scrollbar(self.frame, command=self.tasklist.yview, orient=VERTICAL)
yscroll.grid(row=1, column=1, sticky=N+S)
Without seeing more of your code it's impossible to say. Most likely your listbox is expanding properly, but your self.frame is not. Though, I don't see you giving any weight to the row and column that the listbox is in, so that could be a factor.
An easy way to debug this is to give self.frame a garish color that will stick out (red, bright green, etc). Then it will be easy to see if the listbox is properly resizing inside the frame, and if the frame is properly resizing inside its parent.

Categories

Resources